سؤال

سؤالي يتعلق بالتوازي الأنيق بين الوعود طائر أزرق عندما تحتاج إلى تمرير كل من السياق والوسيطة إلى الوظائف التي تبني الوعود.

ولجعل مشكلتي مفهومة وقابلة للاختبار، قمت بعمل مثال بدون تبعية.

لنفترض أنني أقوم بالحساب ( 1/(xسx) + 1/(x*x)) ) يتضمن "كمبيوتر" غير متزامن (يجب تحرير موارده).يتم حساب المربع والمكعب بشكل غير متزامن ومستقل.

يمكنني إجراء حساباتي مثل هذا:

InitComputer(2) // returns a promise
.then(invert)
.then(function(arg){
    return Promise.all([
        proto.square(arg),
        proto.cube(arg)
    ]);
}).spread(function(sq, cu){
    this.set(sq + cu);
}).catch(function(err){
    console.log('err:', err);
}).finally(endComputer);

لكني أجد هذا الاستخدام لـ all ثقيلة جدًا مقارنة بما هو ممكن نظريًا.عندما تقوم بتمرير دالة كوسيطة إلى then, ، تم تنفيذه.عندما تقوم بتمرير الوظائف إلى all, ، إنهم ليسوا كذلك، هناك خطأ.أظن أنني أفتقد أداة مساعدة أو نمطًا ...

هل هناك حل لتغييره إلى شيء أبسط في هذا النمط:

InitComputer(2)
.then(invert)
.all([
    proto.square,
    proto.cube
]).spread(function(sq, cu){
    this.set(sq + cu);
}).catch(function(err){
    console.log('err:', err);
}).finally(endComputer);

?

ربما يمكنني الاختراق Promise.prototype.all أو تحديد وظيفة جديدة لتجنب زيادة تعدد الأشكال ولكني مهتم فقط بالحلول التي لا تتضمن تعديل الكائنات التي لا أملكها.


المرفق:

إليك كيفية تعريف "الكمبيوتر" للاختبار الخاص بي:

var Promise = require("bluebird");

function Computer(){}
function InitComputer(v){
    // initializing a computer is asynchronous and may fail hence the promise
    var c = new Computer(), resolver = Promise.defer();
    setTimeout(function(){
        if (v>1) resolver.resolve(v);
        else resolver.reject(new Error("bad value: "+v));
    },100);
    return resolver.promise.bind(c);
}
var proto = Computer.prototype;
proto.square = function(x){
    // imagine this really uses the computer and is asynchronous
    if (!this instanceof Computer) throw new Error('not a computer');
    return x*x
}
proto.cube = function(x){ return x*x*x }
proto.set = function(v){ this.value = v }

function endComputer(){
    // releases resources here
    console.log('value:', this.value);
}

// this asynchronous function doesn't involve or know the computer
function invert(v){ return 1/v }
هل كانت مفيدة؟

المحلول

ليس عليك أن تستخدم Promise.all هناك.بدلاً من القيام بما يلي:

.then(function(arg){
    return Promise.all([
        proto.square(arg),
        proto.cube(arg)
    ]);
}).spread(...

يمكنك ببساطة استخدام:

.then(function(arg){
    return [proto.square(arg), proto.cube(arg)];
}).spread(...

إذا كانت لدينا وظائف أسهم في Node.js، فسيكون الأمر بهذه البساطة:

.then(arg => [proto.square(arg), proto.cube(arg)]).spread(...

Promise.all يجب استخدامه عندما تحتاج إلى ذلك يبدأ سلسلة من الوعود تتضمن وعودين على الأقل.على سبيل المثال:

var promise1 = somePromise();
var promise2 = somePromise2();

// Start the chain here
Promise.all([promise1, promise2])
.spread(function(value1, value2) {
    // ...
});

نصائح أخرى

لإدارة حالة استخدام الموارد كما ذكرت، لدى بلوبيرد Promise.using(). Promise.using() يتيح لك الإعداد disposer() وظيفة لإغلاق المورد الذي تم استرداده بشكل غير متزامن تلقائيًا عند الانتهاء من استخدامه

Promise.join() من شأنه أن يساعد كذلك على الجمع بين نتائج cube و square طرق غير متزامنة

أنا هنا إعادة كتابة قليلا الخاص بك InitComputer مثال لتوضيح كيفية عمل ذلك - فهو يُرجع الآن ملف Computer مثيل مع إضافة val كخاصية، بدلاً من val، وقمت بوضعه endComputer على بروتو أيضا

ملحوظة:يمكنك دائما استخدام Promise.method() مثل ذلك بدلاً من إرجاع مؤجل:

var invert = Promise.method(function invert(v){ return 1/v })

كمبيوتر أولي جديد:

function InitComputer(v){
    var c = new Computer(), resolver = Promise.defer();
    setTimeout(function(){
        if (v>1) {
            c.val = v;
            resolver.resolve(c);
        }
        else resolver.reject(new Error("bad value: "+v));
    },100); /** notice resource disposer function added below **/
    return resolver.promise.bind(c).disposer(function(compu){compu.endComputer()});
}

رمز جديد:

Promise.using(InitComputer(1.2), function(computer){
    return invert(computer.val)
    .then(function(inverted){
        return Promise.join(computer.square(inverted), computer.cube(inverted), 
            function(sq, cu){
                computer.set(sq + cu)
            }
        )
    })
    .catch(function(err){
        console.log('err:', err);
    });
})
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top