我的问题是关于承诺的优雅并行化 蓝鸟 当您需要将上下文和参数传递给构建promise的函数时。

为了使我的问题可以理解和测试,我做了一个没有依赖性的例子。

让我们假设我做计算(1/(xxx)+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);

?

我可能会破解 我保证。原型。全部 或者定义一个新函数以避免增加多态性,但我只对不涉及修改我不拥有的对象的解决方案感兴趣。


附件:

以下是如何定义我的测试的"计算机" :

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(...

如果我们在节点中有箭头函数。js,它就像简单的一样:

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

Promise.all 是在你需要的时候使用 开始 至少有2个承诺的承诺链。例如:

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

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

其他提示

对于像您提到的资源用例的管理,bluebird有 Promise.using(). Promise.using() 让您设置 disposer() 当您使用完后,自动关闭异步检索的资源的函数

Promise.join() 将有助于以及结合的结果 cubesquare 异步方法

在这里,我稍微重新写了你的 InitComputer 例子来说明这是如何工作的-它现在返回 Computer 实例与val添加为属性,而不是val,我把 endComputer 在原版也

注意事项:你可以随时使用 Promise.method() 像这样,而不是返回一个延迟:

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

新的initComputer:

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