Promise is one of the best APIs for asynchronous operations in JavaScript. As a JavaScript developer, you need to be proficient in Promise. This article will summarise this knowledge, starting with a review of how JavaScript has handled asynchronous operations in the past? Then we’ll go into detail about the Promises object and its associated methods.
Let’s start with a look at JavaScript asynchronous concepts.
Asynchronous
What is asynchronous? A function is asynchronous if the expected result is not yet available to the caller when the function returns, but will be available in the future by some means (e.g. a callback function).
Asynchronous callbacks
Asynchronous callbacks, commonly known as callbacks, were a common way of handling asynchronous operations in JavaScript in the past, such as AJAX, where an HTTP request was initiated and the exact time when the server returned the response data depended on the client’s environment and there was a lot of uncertainty, when a callback function was used to trigger the callback function when the response data was returned.
This approach is common when there are multiple requests and subsequent requests need to wait for the response data of the previous request when the callback hell occurs.
|
|
The presence of callback hell will cause many problems for project development.
- It will lead to confusing logic, high coupling, one change will lead to all changes, and when nested, bugs are difficult to find.
- You can’t use
try.... .catchto catch exceptions. - Can’t use
returnto return real data
To avoid callback hell, the Promise object was created.
How Promise works
A promise object is an object that can be returned synchronously from an asynchronous function and will be in one of 3 possible states.
fulfilled:onFulfilled()will be called, i.e. the operation is complete (e.g.resolve()is called)rejected:onRejected()will be called, i.e. the operation has failed (e.g.reject()is called)pending: initial state, neither honoured nor rejected
If a promise does not hang (it has been resolved or rejected), it will be resolved. Sometimes resolved and resolved are used to indicate the same thing: not pending.
Once a promise has been determined, it cannot be redetermined, and calling resolve() or reject() again will have no effect. A determined promise has immutability.
For monitoring the state of a promise you can use a promise chain, i.e. in the fulfilled honoured state you can use the then method to get the honoured result, and in the rejected rejected state you can use the catch method to get the reason for the rejection.
It looks a little more elegant than the callback approach, and for needs that require multiple HTTP requests to be initiated for complete rendering, the code looks like this.
|
|
Does the above code feel like déjà vu, originally intended to solve callback hell, but there seems to be a gap between the ideal and the reality.
So ES2021 adds new features to the Promise object, including: Promise.any(), Promise.all(), Promise.allSettled(), and Promise.race().
Promise.any()
Promise.any(promises) runs promise in parallel and resolves to the value of the first successfully resolved promise in the list of promises. Note that the Promise.any() method is still experimental and is not fully supported by all browsers.
Here is a look at how Promise.any() works.
1. How it works
Promise.any() can be used to perform independent asynchronous operations in a parallel and competitive manner to get the value of any first completed promise.
The function accepts an promise array (usually an iterable object) as an argument, as follows.
|
|
When the first promise in the input promises is executed, anyPromise is immediately resolved to the value of that promise.

The value of the first promise can be extracted using the then method.
The async/await syntax can also be used.
The promise returned by romise.any() is executed together with any first promise that is executed. Even if some promises are rejected, these rejections will be ignored.

However, if all promises in the input array are rejected, or if the input array is empty, then Promise.any() will rejected contain the set of rejection error reasons for the execution of the input promises.

2. Usage Guidelines
Before we dive into Promise.any(), let’s define 2 simple functions.
The function
resolveTimeout(value, delay)will return apromisethat hasresolvedafterdelaytime has elapsed.
The function
rejectTimeout(reason, delay)returns apromisethat has arejectafter thedelaytime has elapsed.
Next, try Promise.any() using the 2 helper functions defined above.
2.1 Completing all promises
Try running the first parsed list as follows.
|
|
promise .any([...]) returns a promise that parses the array fruits in 1 second, since the promise that parses the fruits finishes first.
The second is a promise that resolves to the array vegetables in 2 seconds, and its value is ignored.
2.2 A promise is rejected
The first promise above is rejected with an exception, as follows.
|
|
In the above code, the first promise is rejected after 1 second and it is easy to see from the result of the execution that Promise.any() skips the first promise that is rejected and waits for the second promise that finishes 2 seconds later.
2.3 All promises are rejected
Here’s what happens when all promises are rejected, with the following code.
|
|
Summary
Promise.any() can be used to execute independent asynchronous operations in parallel in a competitive manner to obtain the value of any first promise that completes successfully. If all input promises to Promise.any() have been rejected, then the promise returned by the helper function will also be rejected as an aggregate error, which contains the reason for the rejection of the input promise in a special property AggregateError: aggregateError.errors .
Promise.all()
method Promise.all(promises), can process multiple promises at once in parallel and return only one promise instance, the result of the resolve callback for all the promises entered is an array.
Here’s how Promise.all() works.
1. How it works
Promise.all() is a built-in helper function that takes a set of promises (or an iterable object) and returns a promise: Promise.all() is a built-in helper function that takes a set of promises (or an iterable object) and returns a promise.
|
|
The value of the first promise can be extracted using the then method.
The async/await syntax can also be used.
The way in which the promise returned by Promise.all() was parsed or rejected.
If allPromise are all successfully parsed, then allPromise will use as its result an array containing the values of each promise after it has been executed. The order of the promises in the array is important - the implemented values will be obtained in this order.

But if at least one promise is rejected, then allPromise is immediately rejected for the same reason (without waiting for the execution of other promises).

If all promises are rejected, wait for all promises to finish, but only return the reject reason for the first promise that was rejected.

2. Usage Guidelines
Before we dive into Promise.all(), let’s define 2 simple functions.
The function
resolveTimeout(value, delay)will return apromisethat hasresolvedafterdelaytime has elapsed.
The function
rejectTimeout(reason, delay)returns apromisethat has arejectafter thedelaytime has elapsed.
Next, try Promise.all() using the 2 helper functions defined above.
2.1 Completing all promises
An promise array allPromise is defined below, and all promises are capable of successful resolve values, as follows.
|
|
The result of the above execution shows that the resolve array of promise returned by Promise.all() is composed in the order of allPromise before it is executed.
The order of the
promisearrays directly affects the order of the result, regardless of the order in which the execution ofpromisecompletes.
2.2 A promise is rejected
The first promise of the array allPromise above is rejected with an exception, as follows.
|
|
However, after 5 seconds, the first promise is rejected due to an exception, causing allPromise to be rejected as well, and returning the same error message as the first promise: Error: fruits is empty, even though the value of the second promise after 1 second is completed, the value of the second promise is not accepted.
Next, all the promises in the array allPromise are thrown with an exception and rejected, and the order of rejected is adjusted by the timer as follows.
|
|
After 5 seconds, the execution completes and the result is Error: vegetables is empty, it is easy to see that allPromise was rejected because the promise that was rejected first.
This behaviour of > Promise.all() is known as fast failure, and if at least one promise in the promise array is rejected, then the returned promise is also rejected. If all of the promise arrays are rejected, then the returned promise is rejected because of the one that was rejected first.
Summary
Promise.all() is the best way to perform asynchronous operations in parallel and get all the resolve values, ideal for situations where you need to get the results of the asynchronous operations simultaneously to perform the next operation.
Promise.allSettled()
method Promise.allSettled(promises), returns a promise after all the given promises have been fulfilled or rejected, with an array of objects, each representing the corresponding promise result.
Here’s how Promise.allSettled() works.
1. How it works
Promise.allSettled() can be used to execute independent asynchronous operations in parallel and collect the results of those asynchronous operations.
The function accepts an promise array (or usually an iterable one) as an argument, as follows.
|
|
When all input promises have been fulfilled or rejected, statusesPromise is resolved to an array with its status.
{ status: 'fulfilled', value:value }: if the correspondingpromisehas been fulfilled{ status: 'rejected', reason: reason }: if the correspondingpromisewas rejected

The state of all promises can be extracted using the then method.
The async/await syntax can also be used.
The promise returned by Promise.allSettled() is always realized with a range of states, regardless of whether some (or all) of the input promises are rejected.
The big difference between
Promise.allSettled()andPromise.all():Promise.allSettled()will never berejected.
2. Usage Guidelines
Before we dive into the use of Promise.allSettled(), let’s define 2 simple functions.
Next, try Promise.allSettled() using the 2 helper functions defined above.
2.1 Completing all promises
An promise array statusesPromise is defined below, and all promises are capable of successful resolve values, as follows.
|
|
From the results of the above execution Promise.allSettled() returns an array of resolve states of a promise in the order in which the statusesPromise were composed before it was executed.
2.2 A promise is rejected
The first promise above is rejected with an exception, with the following code.
|
|
Even if the second promise in the input array is rejected, statusesPromise can still successfully parse the state array.
2.3 All promises are rejected
All of the above promises with exceptions are rejected, with the following code.
|
|
Summary
Promise.allSettled() is a good choice when parallel and independent asynchronous operations need to be performed and all results collected, even if some asynchronous operations may fail.
Promise.race()
method Promise.race(promises), as the name implies, means race, Promise.race([p1, p2, p3] fetches the result of whichever of the promise arrays completes faster, regardless of whether the result itself is a successful fulfillment or a failed rejection state, and outputs only the fastest promise.
Here’s how Promise.race() works.
1. How it works
Promise.race() returns a promise that will be fulfilled or rejected once one of the promises in the iterator has been fulfilled or rejected.
The function accepts an promise array (or usually an iterable) as an argument, as follows.
|
|
When one of all input promises is quickly fulfilled or rejected, racePromise resolves the fast-completing promise result (fulfilled or rejected) as follows.


The result of racePromise can be extracted using the then method.
The async/await syntax can also be used.
Promise.race() Returns a promise with the same information as the first promise to complete.
Difference between
Promise.race()andPromise.any():Promise.race()looks for the first fulfilled or rejected promise in the list of promises;Promise.any()looks for the first fulfilled promise from the list of promises.
2. Usage Guidelines
Before we dive into the use of ``Promise.race()`, let’s define 2 simple functions as well.
Next, try Promise.race() using the 2 helper functions defined above.
2.1 Completing all promises
An promise array racePromise is defined below, and all promises are capable of successful resolve values as follows
|
|
From the above execution Promise.race() returns the resolve result of the fastest performing promise.
2.2 A promise is rejected
The first promise above is rejected with an exception, as follows.
|
|
From the above result, the first promise to complete is rejected, so the promise returned by fastPromise is also rejected.
The following extends the promise time for rejected to 5 seconds, as follows.
|
|
As you can see from the above results, the fastest completed promise fulfilled resolve, so the promise returned by fastPromise also fulfilled resolve.
2.3 All promises are rejected
All the promises above are rejected with an exception, as follows.
|
|
From the results, although both promises were rejected, the promise returned by fastPromise was the fastest to be rejected.
3. Usage scenarios
3.1. Performance testing
In projects with asynchronous operations, you can use Promises to test the performance of network or database requests by using Promise.race() to test the responsiveness of the two different methods.
3.2 Optimal choices
For example fetching the same type of data with multiple requesting servers, sending requests to multiple servers at the same time and rendering their data as soon as one of them completes its work, to achieve the effect of choosing the best route. This is done by using Promise.race() to execute promise at the same time and finish as soon as the first one succeeds.
Summary
Promise.race() executes a callback function for the first resolved and rejected promise, while Promise.any() executes a callback function for the first fulfilled promise and rejects a special property AggregateError if the unfulfilled promise is rejected.