Bluebird Promise.all - multiple promises completed aggregating success and rejections

22,583

You'd use .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()
     }
  });
});

This used to be handled with a settle function that did this for an array traditionally - it was generalized by .reflect since it separates aggregation from the notion of a promise inspection and lets you do what .settle did but to other actions like .any or .some as well.

Share:
22,583
j03m
Author by

j03m

Updated on March 10, 2020

Comments

  • j03m
    j03m about 4 years

    Someone brought up an interesting case today with bluebird, what is the best way to handle multiple promises where we're not interested in stopping on a given fulfillment or rejection but rather interested in inspecting the final result. An example:

    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);
    });
    

    Here, if we run either map or all the rejected promises will cause handlers not to report results.

    For example the results of running Promise.map as implemented above is:

    debugger listening on port 65222
    p1
    results: yay
    p2
    Error: [Error: boo]
    p3
    p4
    
    Process finished with exit code 0
    

    Here the code for each promise executes, but only 1 result and 1 error is reported. The error causes the process to stop.

    If we uncomment .all we get similar behavior. This time, only the error is reported. Any successes do not make it into then (understandably).

    debugger listening on port 65313
    p1
    p2
    Error: [Error: boo]
    p3
    p4
    
    Process finished with exit code 0
    

    Given this behavior what would be the best way to go about implementing a scenario where by all promises are run and the results of fulfilled promises are reported with any and all rejections?

    Something like:

    Promise.aggregate([p1,p2,p3,p4]).then(function(fulfilled, rejected){
        console.log(fulfilled); //all success
        console.log(rejected); //any and all rejections/exceptions
    });
    
  • silverlight513
    silverlight513 about 8 years
    I don't think .settle is supported by bluebird anymore, there's no mention of it in their docs.
  • Benjamin Gruenbaum
    Benjamin Gruenbaum about 8 years
    @silverlight513 yes sorry, we deprecated settle - it'll still work though. The way forward is to use .reflect. Thanks for bringing this to my attention I'll update the answer.
  • Sam
    Sam almost 8 years
    @BenjaminGruenbaum .reflect is not working for me in the latest version. Specifically I get a Uncaught TypeError: promise.reflect is not a function error when I run even the docs example as it is. Someone else asked about .reflect as well. Hmm.