Explain Codes LogoExplain Codes Logo

Handling errors in Promise.all

javascript
promise-engineering
interview-preparation
best-practices
Nikita BarsukovbyNikita Barsukov·Feb 9, 2025
TLDR

Use Promise.allSettled to handle multiple promises without stopping after the first rejection. It provides results in the form { status: 'fulfilled', value: ... } for successful promises, or { status: 'rejected', reason: ... } for errors. Iterating over the results helps cater for each case specifically.

Promise.allSettled([promise1, promise2, promise3]).then((results) => { results.forEach(({ status, value, reason }) => status === 'fulfilled' ? console.log('Success:', value) : console.error('Error:', reason) ); });

As you can see, this method allows you to design responses to both success and failure within the same callback for efficient error handling.

Detailed walkthrough and common pitfalls

In a world where Promise.all exists, it's important to remember its eager rejection nature. If one promise fails, the entire chain flies off the handle. To prevent this wild behavior, you can attach individual catch() methods to each promise:

// Hey look! An error catching function! const withCatch = (promise) => promise.catch(e => ({ error: e })); // Who you gonna call? Error Handlers! const promises = [promise1, promise2, promise3].map(withCatch); Promise.all(promises).then(results => { results.forEach(result => result.error ? console.error('Error handled like a pro:', result.error) : console.log('Success:', result) ); });

No promise left behind

In the wild world of mixed promise-value arrays, it's always good to remember to treat everyone equally. Here's how to ensure everyone is wrapped snugly into the warmth of being a promise:

const ensurePromise = (item) => Promise.resolve(item).catch(e => e); const mixedArray = [value1, promise1, value2].map(ensurePromise); Promise.allSettled(mixedArray).then(resultsHandlingFunction);

Time to unwrap the presents

Post-processing in Promise.allSettled() lets you unwrap the statuses and see what's inside:

Promise.allSettled(promises) .then((results) => results.map(result => result.status === 'fulfilled' ? result.value : handleErrorFlipAndReverseIt(result.reason) ));

Backward compatibility is cool

If you have to work in old school environments that don't have Promise.allSettled(), fear not! You can use polyfills or libraries such as promise.allsettled or Bluebird. While you're at it, don't forget to look cool for the future by staying compatible:

if (!Promise.allSettled) { Promise.allSettled = promises => Promise.all(promises.map(p => p.then( value => ({ status: 'fulfilled', value }), reason => ({ status: 'rejected', reason }) ))); }

Manage errors like a pro

We can level up our error handling by mapping over results to get extended diagnostic message:

Promise.allSettled(promises).then(results => { results.forEach((result, index) => { if (result.status === 'rejected') { console.error(`Error inside promise ${index + 1}:`, result.reason); } }); });

Stay sharp, avoid pitfalls

Hidden coding errors - the ninjas of programming nightmares - can break your promise chains. Here are some tips to keep them at bay:

  • Be the terminator of promises - end every then() with a catch().
  • Don't forget to return the promises within a then().
  • Stay alert and keep an eye on the console output.