蓝鸟承诺.all - 多个承诺完成聚合成功和拒绝

30

今天有人提出了一个关于bluebird的有趣案例,我们应该如何处理多个promise,其中我们对于停止在某个fulfillment或rejection上并不感兴趣,而是对检查最终结果感兴趣。以下是一个示例:

var p1 = new Promise(function(f,r){
    setTimeout(function(){
        console.log("p1");
        f("yay");
    }, 100);

});

var p2 = new Promise(function(f,r){
    setTimeout(function(){
        console.log("p2");
        r(new Error("boo"));
    }, 200);

})

var p3 = new Promise(function(f,r){
    setTimeout(function(){
        console.log("p3");
        r(new Error("yay"));
    }, 300);

});

var p4 = new Promise(function(f,r){
    setTimeout(function(){
        console.log("p4");
        f("yay");
    }, 400);

});


//Promise.all([p1,p2, p3, p4]).then(function(p){
//    console.log("Results:",p);
//}).error(function(e){
//    console.log("Error:",e);
//});

Promise.map([p1,p2, p3, p4],function(p){
    console.log("results:",p);
}, {concurrency:10}).error(function(e){
    console.log("Error:",e);
});

如果我们运行map或所有被拒绝的承诺都会导致处理程序不报告结果。

例如,上面实现的Promise.map运行的结果是:

debugger listening on port 65222
p1
results: yay
p2
Error: [Error: boo]
p3
p4

Process finished with exit code 0

这里每个 Promise 的代码都会执行,但只有一个结果和一个错误被报告。错误导致进程停止。

如果我们取消 .all 的注释,我们会得到类似的行为。这次,只有错误被报告。任何成功的操作都不会进入 then 方法(可以理解)。

debugger listening on port 65313
p1
p2
Error: [Error: boo]
p3
p4

Process finished with exit code 0

考虑到这种行为,实现一种场景的最佳方式是什么,其中所有承诺都会运行,并报告实现的承诺结果及任何拒绝的情况?

例如:

Promise.aggregate([p1,p2,p3,p4]).then(function(fulfilled, rejected){
    console.log(fulfilled); //all success
    console.log(rejected); //any and all rejections/exceptions
});
1个回答

39
您可以使用.reflect方法:
Promise.all([p1,p2,p3,p4].map(x => x.reflect()).then(results => {
  results.forEach(result => {
     if(result.isFulfilled()){
         // access result.value()
     } else {
         // access result.reason()
     }
  });
});

以前这通常通过一个settle函数来处理数组 - 由于将聚合与承诺检查的概念分开并允许您执行像.settle所做的操作,因此它被.reflect泛化了。而且您也可以对其他动作进行聚合,例如.any.some


1
我认为Bluebird不再支持.settle,因为在他们的文档中没有提到它。 - silverlight513
2
@silverlight513 对不起,我们已经弃用了 settle,但它仍然可以工作。未来的方向是使用 .reflect。感谢您提醒我,我会更新答案。 - Benjamin Gruenbaum
4
在最新版本中,.reflect 对我来说无法工作。即使按照文档示例运行,我也会收到 Uncaught TypeError: promise.reflect is not a function 错误。其他人也提出了关于 .reflect 的问题。 - Sam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接