Difference Between Promise.all and Promise.allSettled


Promise.all and Promise.allSettled act differently. Let's explore this beautiful variety:

Test Harness

Let's set up a little test to see what the differences are. This test has some Promises that fail (and reject) and some Promises that win (and resolve).

Where it's set up now to Promise.all, in later experiments, we'll change it to Promise.allSettled.

function fail(ms = 1000) {
  return new Promise((_resolve, reject) => {
    setTimeout(() => {
      console.log("Failing now");
      reject("Failed");
    }, ms);
  });
}

function win(ms = 1000) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("Winning now");
      resolve("Won");
    }, ms);
  });
}

(async function main() {
  try {
    // prettier-ignore
    const thing = await Promise.all([
      win(1000), 
      fail(2000), 
      win(3000)
    ]);
    console.log("resolved with", thing);
  } catch (err) {
    console.log("rejected with", err);
  }
})();

How Promise.all Acts

When we run the test with Promise.all, we get this output:

❯ node test.js
I'm going to win
I'm going to fail
I'm going to win
Winning now
Failing now
rejected with Failed
Winning now

Things to notice:

  • It rejects on the first failure.
  • Async operations (the setTimeout callbacks) still run (eg, 2nd 'Winning now').
  • It doesn't wait for all promises to resolve.
  • When Promise rejects, the Promise is caught.

If we change the experiment a bit to remove the failure:

const thing = await Promise.all([
  win(1000), 
  win(3000)
]);

The output is:

❯ node test.js 
Winning now
Winning now
resolved with [ 'Won', 'Won' ]

Notice:

  • With no failures, all resolved values come back in one array.

How Promise.allSettled Acts

If we change the experiment to use Promise.allSettled:

const thing = await Promise.allSettled([
  win(1000), 
  fail(2000), 
  win(3000)
]);

And then run, we get:

❯ node test.js
Winning now
Failing now
Winning now
resolved with [
  { status: 'fulfilled', value: 'Won' },
  { status: 'rejected', reason: 'Failed' },
  { status: 'fulfilled', value: 'Won' }
]

What it did:

  • It always resolves, even when one of the Promises rejects.
  • It guarantees resolution of all Promises before it, itself resolves.
  • An array is returned that contains objects with the status of each promise resolution, be it resolved or rejected.

When to Use

Use Promise.all when:

You want quick returns, knowing when any of the Promises have failed. The rest will run, but you'll know as soon as you can about the first problem.

Use Promise.allSettled when:

You want to know the resolution value of each and every Promise, whether failed or successful, and you're willing to wait however long that takes.

It seems to me that Promise.allSettled usage is more-commonly useful, but I tend to see more Promise.all in code in practice.