Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling errors in Promise.all

I have an array of Promises that I'm resolving with Promise.all(arrayOfPromises);

I go on to continue the promise chain. Looks something like this

existingPromiseChain = existingPromiseChain.then(function() {   var arrayOfPromises = state.routes.map(function(route){     return route.handler.promiseHandler();   });   return Promise.all(arrayOfPromises) });  existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {   // do stuff with my array of resolved promises, eventually ending with a res.send(); }); 

I want to add a catch statement to handle an individual promise in case it errors, but when I try, Promise.all returns the first error it finds (disregards the rest), and then I can't get the data from the rest of the promises in the array (that didn't error).

I've tried doing something like ..

existingPromiseChain = existingPromiseChain.then(function() {       var arrayOfPromises = state.routes.map(function(route){         return route.handler.promiseHandler()           .then(function(data) {              return data;           })           .catch(function(err) {              return err           });       });       return Promise.all(arrayOfPromises)     });  existingPromiseChain = existingPromiseChain.then(function(arrayResolved) {       // do stuff with my array of resolved promises, eventually ending with a res.send(); }); 

But that doesn't resolve.

Thanks!

--

Edit:

What the answers below said were completely true, the code was breaking due to other reasons. In case anyone is interested, this is the solution I ended up with ...

Node Express Server Chain

serverSidePromiseChain     .then(function(AppRouter) {         var arrayOfPromises = state.routes.map(function(route) {             return route.async();         });         Promise.all(arrayOfPromises)             .catch(function(err) {                 // log that I have an error, return the entire array;                 console.log('A promise failed to resolve', err);                 return arrayOfPromises;             })             .then(function(arrayOfPromises) {                 // full array of resolved promises;             })     }; 

API Call (route.async call)

return async()     .then(function(result) {         // dispatch a success         return result;     })     .catch(function(err) {         // dispatch a failure and throw error         throw err;     }); 

Putting the .catch for Promise.all before the .then seems to have served the purpose of catching any errors from the original promises, but then returning the entire array to the next .then

Thanks!

like image 344
Jon Avatar asked May 21 '15 00:05

Jon


People also ask

How does promise all handle errors?

Promise. all is all or nothing. It resolves once all promises in the array resolve, or reject as soon as one of them rejects. In other words, it either resolves with an array of all resolved values, or rejects with a single error.

What happens if a promise fails in promise all?

all(promises) – The function waits for all promises to resolve and returns the array of their results. If any of the given promises rejects, it becomes an error of the Promise. all() method and all other results are ignored.

What is the use of promise all ()?

The Promise. all() method is actually a method of Promise object (which is also an object under JavaScript used to handle all the asynchronous operations), that takes an array of promises(an iterable) as an input.

Does promise all stop execution?

all to Stop Async/Await from Blocking Execution in JS. When writing asynchronous code, async/await is a powerful tool — but it comes with risks! Learn how to avoid code slowdowns in this tutorial.


2 Answers

Promise.all is all or nothing. It resolves once all promises in the array resolve, or reject as soon as one of them rejects. In other words, it either resolves with an array of all resolved values, or rejects with a single error.

Some libraries have something called Promise.when, which I understand would instead wait for all promises in the array to either resolve or reject, but I'm not familiar with it, and it's not in ES6.

Your code

I agree with others here that your fix should work. It should resolve with an array that may contain a mix of successful values and errors objects. It's unusual to pass error objects in the success-path but assuming your code is expecting them, I see no problem with it.

The only reason I can think of why it would "not resolve" is that it's failing in code you're not showing us and the reason you're not seeing any error message about this is because this promise chain is not terminated with a final catch (as far as what you're showing us anyway).

I've taken the liberty of factoring out the "existing chain" from your example and terminating the chain with a catch. This may not be right for you, but for people reading this, it's important to always either return or terminate chains, or potential errors, even coding errors, will get hidden (which is what I suspect happened here):

Promise.all(state.routes.map(function(route) {   return route.handler.promiseHandler().catch(function(err) {     return err;   }); })) .then(function(arrayOfValuesOrErrors) {   // handling of my array containing values and/or errors.  }) .catch(function(err) {   console.log(err.message); // some coding error in handling happened }); 
like image 181
jib Avatar answered Oct 16 '22 11:10

jib


NEW ANSWER

const results = await Promise.all(promises.map(p => p.catch(e => e))); const validResults = results.filter(result => !(result instanceof Error)); 

FUTURE Promise API

  • Chrome 76: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
  • You can download https://www.npmjs.com/package/promise.allsettled to get it now. In certain browsers allSettled comes preinstalled with the browser itself. It's worth downloading the package for peace of mind because eg. TypeScript doesn't have default definitions for allSettled.
like image 32
Solominh Avatar answered Oct 16 '22 10:10

Solominh