Introduction
The advent of Promise to JavaScript in ES6 has bought significant benefits to developers, notably taking away the pain of handling callback hells, and making asynchronous JavaScript easier to use and reason about for new developers. Also, it came with two very handy methods Promise.all and Promise.race if you are trying to carry out multiple asynchronous actions at the same time.
And as the language evolves, two additional methods had been added Promise.allSettled (ES2020) and Promise.any (ES2021) for handling simultaneous multiple asynchronous actions under different conditions. They are compatible in many modern browsers Promise.all, Promise.race, Promise.allSettled, Promise.any.
However, with so many variants now available, confusions may arise for many developers as to which one would be best for their applications. To alleviate these confusions, this article highlights the key features of these variants and discuss their differences, so as to help developers to make the right choice.
In aim of this the article is going to:
- Explain the key features and the differences between these four methods
- How to pick the right method for your situation
TL;DR
Settled in the context of Promise means that it is not in the pending state and could be either rejected or fulfilled.
All four methods
- take an iterable of promises as an input
- return a single promise
However, the results are in slightly different form:
Promise.all (Short Circuit) -> an array of values from all resolved promises or (Short Circuited) one single value from the first rejected promise.
Promise.race (Short Circuit) -> (Short Circuited) a single value from the first resolved or reject promise.
Promise.allSettled (No Short Circuit) -> an array of objects with property status and reason(rejected) or value(resolved)
Promise.any (Short Circuit) -> (Short Circuited) a single value from the first resolved promise or AggregateError that contains an array of values from all rejected promises.
The Differences
I expected readers reading this article already have a basic understanding of Promise but just to refresh your memories, I am going to briefly describe some basics of Promise.
A Promise can be in one of the three states, pending, fulfilled and rejected: pending is the initial state, fulfilled, a successfully completed operation and fulfilled with a value, rejected a failed operation and with a reason.
Promise handlers such as .then and .catch can be attached to the Promise and will be called after the Promise has been fulfilled or rejected. These two handlers also return a Promise, allowing the chaining of multiple handlers.
On rejection, we can handle it with .catch or .then(..., onRejection).
To illustrate and to compare how these variants works, scenarios with different input and expected output are used, as shown in the following tables.
Three promises with the following values and settle time are used in these scenarios:
Promise 1(P1) with value/ reason 1 settle in 1s
Promise 2(P2) with value/ reason 2 settle in 2s
Promise 3(P3) with value/ reason 3 settle in 3s
Notes:
- SC- short-circuited
- β- rejected
- β - fulfilled
- β- pending
Scenario 1- All Promises Fulfilled Successfully
Scenario 2- First Promise Rejected
Scenario 3- Second Promise Rejected
Scenario 4- All Promises Rejected
Some clear observations can be readily obtained from these tables:
-
Short-Circuit
.racewill always be short-circuited once the first promise settled.- the rest of the methods will wait for their own conditions to be fulfilled.
-
Return Value(s)
.allSettledalways return an array containing an object for each promise..racealways return a single value.
-
.anyand.all- almost behaving opposite of each other,
.anywill short-circuit on the first fulfilled promise, while.allwill short-circuit on the first reject promise. - if all rejected,
.anywill return an AggregateError containing all the rejected promises and if all fulfilled,.allwould return an array of fulfilled promises.
- almost behaving opposite of each other,
How to Use
.race - when you only want whatever the first outcome from the first settled promise.
.all - when you want to get back all the successfully fulfilled promises and stop the operation when there is a single rejection. Mostly used if these tasks are dependent on each other.
.allSettled - when you want to wait for all the promises to be settled and you want to handle it in your own way or apply any filtering from the outcome. Contrary to .all is mostly used for tasks which are not dependent on each other.
.any - when you only want the first successfully fulfilled promise or handle all the rejected promises AggregateError.
