6

Given the following

Promise.all(promises).then(resolved => {
    ...
}).catch(rejected => {
    ...
});

rejected will only contain the first promise to be rejected. Is there a way to catch all promises that are rejected?

Chris_F
  • 4,991
  • 5
  • 33
  • 63
  • 1
    individually, yes, but not with .all. As you've found, the first rejected promise throws the catch; it doesn't wait from them all to finish. You would have to loop over each promise and attach catch handlers to each, then somehow figure out when they've all completed (because .all at that point would be useless) – Kevin B Nov 28 '16 at 18:55
  • `rejected` won't contain the first promise to be rejected--it will contain the **reason** it was rejected. –  Nov 28 '16 at 19:07
  • 1
    See also [this question](http://stackoverflow.com/questions/37902927/resolve-and-reject-all-promises-in-bluebird) on how this case can be treated with Bluebird. Inspections make the things easier. – Estus Flask Nov 28 '16 at 19:11
  • @naomik I guess you could have kept your answer, though it would come down to rewriting it, basing `reconcile` on `Promise.settle` or something [like this](http://stackoverflow.com/a/30930421/1048572). You could keep the examples from the first section, and the "how this differs" part. – Bergi Nov 29 '16 at 22:05

2 Answers2

21

Of course, doing this will require waiting until all the input promises have settled. As long as one is pending, which might reject, you can't be sure you have all the rejections!

So you can use Promise.all, but after transforming the input promises so as to catch rejections and identify them, perhaps by wrapping them in an Error object, as in

caughtPromises = promises.map(promise => promise.catch(Error));

Now filter the results of Promise.all to find the ones identified as failing:

Promise.all(caughtPromises)
  .then(results => results.filter(result => result instanceof Error))

et voilà.

1

The usual way to wait for all promises to be settled (resolved or rejected) is to use something like Promise.settle(). You can see several different variations of it here: ES6 Promise.all() error handle - Is .settle() needed?

The basic concept is that you wrap each of your promises with a wrapper that catches (and saves) their rejections and turns them into resolves and then you pass those resulting promises to Promise.all(). Since all the promises you are passing to Promise.all() will resolve (none will reject), it will wait for all of them. But, then the resulting value will be an array that you can iterate over to see which promises resolved and which rejected:

You would them use it like this:

Promise.settle(arrayOfPromises).then(function(results) {
    results.forEach(function(pi, index) {
        if (pi.isFulfilled()) {
            console.log("p[" + index + "] is fulfilled with value = ", pi.value());
        } else {
            console.log("p[" + index + "] is rejected with reason = ", pi.reason());
        }
    });
});

See the above linked posting for the actual code for Promise.settle() to avoid repeating it here.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979