JavaScript Promise: .all() vs .allSettled() and .race() vs .any()
Shameel Uddin
Posted on August 26, 2023
In previous articles we learned about how Promise work and discussed about then
catch
and finally
methods.
Today we will be discussing:
- Promise.all()
- Promise.allSettled()
- Difference + Usecase of Promise.all() and Promise.allSettled()
- Promise.race()
- Promise.any()
- Difference + Usecase of Promise.race() and Promise.any()
All these methods take array of promises
as an input
but deals differently with respect to their behavior.
By mastering these methods, you'll have a versatile toolkit at your disposal, which will allow you to manage complex asynchronous operations.
Promise.all()
Promise.all
method in JavaScript is used to handle multiple promises concurrently and wait for all of them to resolve.
ALL PROMISES MUST BE RESOLVED FOR IT TO RETURN A RESPONSE. Never forget that. =)
If all promises resolve then it returns an array with all resolved promises.
Let's take an example with the code:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.all(promisesArray)
.then((results) => {
console.log("All promises resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
In this snippet, we have three promises which resolve after 500
, 800
and 1000
milliseconds. Since all of them are going to be resolved so you will see the log like this after you run this snippet:
All promises resolved: [ 'Promise 1 resolved', 'Promise 2 resolved', 'Promise 3 resolved' ]
If any of the promise rejects, it won't wait for others to resolve and will return with reason of the promise that is rejected. Look at example below to get the better idea about this:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((_, reject) =>
setTimeout(() => reject("Promise 3 rejected"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.all(promisesArray)
.then((results) => {
console.log("All promises resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
Here, promise2
resolves after 500
seconds but promise3
rejects after 800
seconds so it will not wait for promise1
and will return a response:
At least one promise rejected: Promise 3 rejected
Promise.allSettled()
The Promise.allSettled
method is used to handle multiple promises concurrently, just like Promise.all
, but it waits for all the promises to settle (either resolve or reject) before proceeding. It returns an array of objects representing the outcomes of the input promises, including their values or reasons for rejection.
Promise.allSettled()
always returns array of objects
with status
key which denotes fulfilled
or rejected
. If a promise is fulfilled
then you can get response with value
key and if the promise is rejected then you can find the reason in reason
key.
Look at this code:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.allSettled(promisesArray).then((results) => {
console.log("All promises settled:", results);
});
You will see a response like this:
[
{ status: 'fulfilled', value: 'Promise 1 resolved' },
{ status: 'fulfilled', value: 'Promise 2 resolved' },
{ status: 'fulfilled', value: 'Promise 3 resolved' }
]
Now we will try and reject promise2
like we did previously and see the response:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((_, reject) =>
setTimeout(() => reject("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.allSettled(promisesArray).then((results) => {
console.log("All promises settled:", results);
});
Response:
[
{ status: 'fulfilled', value: 'Promise 1 resolved' },
{ status: 'rejected', reason: 'Promise 2 resolved' },
{ status: 'fulfilled', value: 'Promise 3 resolved' }
]
Difference between Promise.all() and Promise.allSettled()
We have uncovered the difference of these two already with the coding approach; lets further theoretically discuss these
The Promise.all
and Promise.allSettled
methods are both used to work with multiple promises, but they have different behaviors when it comes to handling resolved and rejected promises. Here are the key differences between the two methods:
Handling Rejected Promises:
Promise.all: If any of the input promises is rejected, the entire returned promise will immediately reject with the reason of the first rejected promise. The resolution of Promise.all
depends on all promises being fulfilled successfully.
Promise.allSettled: The returned promise always resolves, regardless of whether individual promises were fulfilled or rejected. The result is an array of objects representing the outcomes of all input promises, including both fulfilled and rejected ones.
Resolution Behavior:
Promise.all: Resolves only if all input promises are resolved successfully. The resolved value is an array containing the resolved values of the input promises in the same order.
Promise.allSettled: Resolves with an array of objects, one for each input promise. These objects contain the status of each promise ("fulfilled" or "rejected") along with the value (if resolved) or reason (if rejected).
Use Cases:
Promise.all: Useful when you want to wait for multiple asynchronous operations to complete and need all of them to be successful before proceeding. For example, making multiple API requests in parallel and waiting for all responses.
Promise.allSettled: Useful when you want to gather the results of multiple asynchronous operations, regardless of whether they succeeded or failed. It's often used when you want to know the outcome of all promises, even if some of them are rejected.
Promise.race()
As the name suggests, race
returns first promise with shortest delay
whether it is resolved
or rejected
.
For example if there are 5 promises which returns result like this:
Promise 1 ==> 1 second (rejected)
Promise 2 ==> 2 seconds (rejected)
Promise 3 ==> 3 seconds (resolved)
Promise 4 ==> 4 seconds (resolved)
Promise 5 ==> 5 seconds (resolved)
So, it will return us Promise 1 because it was the first one being returned.
A more formal way to put it is this:
The Promise.race
method in JavaScript is used to handle multiple promises concurrently, but it resolves or rejects as soon as the first promise in the input array settles, either by resolving or rejecting.
This can be useful when you're interested in the result of the first promise to complete, regardless of whether it's a success or failure.
Lets look at this example where the first promise resolves:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.race(promisesArray)
.then((results) => {
console.log("First promise resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
You should see a response like this:
First promise resolved: Promise 2 resolved
Lets look at this example where the first promise rejects:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((_,reject) =>
setTimeout(() => reject("Promise 2 rejected"), 500)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.race(promisesArray)
.then((results) => {
console.log("First promise resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
You should see a response like this:
At least one promise rejected: Promise 2 rejected
Please note: race
does not care if all are resolved or all are rejected. It will give you first settled result whether it is resolved or rejected.
Promise.any()
It is somewhat similar to race
method but with few minor differences:
- It will return with first resolved promise.
For example if there are 5 promises which returns result like this:
Promise 1 ==> 1 second (rejected)
Promise 2 ==> 2 seconds (rejected)
Promise 3 ==> 3 seconds (resolved)
Promise 4 ==> 4 seconds (resolved)
Promise 5 ==> 5 seconds (resolved)
So, it will return us Promise 3 because it was the first one being resolved.
- If all promises are rejected, it will give you an aggregated error.
For example if there are 5 promises which returns result like this:
Promise 1 ==> 1 second (rejected)
Promise 2 ==> 2 seconds (rejected)
Promise 3 ==> 3 seconds (rejected)
Promise 4 ==> 4 seconds (rejected)
Promise 5 ==> 5 seconds (rejected)
So, now it will return an aggregated result like this:
[AggregateError: All promises were rejected]
Lets look at first example:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 2 resolved"), 500)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.any(promisesArray)
.then((results) => {
console.log("First promise resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
You will find a similar response as race
method:
First promise resolved: Promise 2 resolved
Lets look at another example:
const promise1 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 1 resolved"), 1000)
);
const promise2 = new Promise((_,reject) =>
setTimeout(() => reject("Promise 2 rejected"), 500)
);
const promise3 = new Promise((resolve) =>
setTimeout(() => resolve("Promise 3 resolved"), 800)
);
const promisesArray = [promise1, promise2, promise3];
If you run this snippet in which the promise with shortest delay promise2
of 500ms
is rejected and promise3
which has next shortest delay 800ms
then:
-
race
will returnpromise2
with rejected reason -
any
will returnpromise3
with resolved result.
Run it with promise.any
:
Promise.any(promisesArray)
.then((results) => {
console.log("First promise resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
You will get this response:
First promise resolved: Promise 3 resolved
Run it with promise.race
:
Promise.race(promisesArray)
.then((results) => {
console.log("First promise resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
You will get this response:
At least one promise rejected: Promise 2 rejected
Below is the case of all promises being rejected with promise.any
:
const promise1 = new Promise((_, reject) =>
setTimeout(() => reject("Promise 1 rejected"), 1000)
);
const promise2 = new Promise((_, reject) =>
setTimeout(() => reject("Promise 2 rejected"), 500)
);
const promise3 = new Promise((_, reject) =>
setTimeout(() => reject("Promise 3 rejected"), 800)
);
const promisesArray = [promise1, promise2, promise3];
Promise.any(promisesArray)
.then((results) => {
console.log("First promise resolved:", results);
})
.catch((error) => {
console.error("At least one promise rejected:", error);
});
Then you will see a response like this:
At least one promise rejected: [AggregateError: All promises were rejected] {
[errors]: [ 'Promise 1 rejected', 'Promise 2 rejected', 'Promise 3 rejected' ]
}
In contrast, the same code with race
method will return this:
At least one promise rejected: Promise 2 rejected
Difference between Promise.race() and Promise.any()
We have already uncovered the differences of race
and any
in coding, lets further discuss them theoretically:
Both Promise.race
and Promise.any
are methods used to handle multiple promises concurrently, but they have different behaviors when it comes to resolving and rejecting. Here are the key differences between the two methods:
Resolution Behavior:
Promise.race: Resolves as soon as the first promise in the input array settles, whether it's resolved or rejected. The returned promise adopts the outcome (either resolve or reject) of the first settled promise.
Promise.any: Resolves as soon as any one of the input promises resolves. It doesn't matter if the other promises reject. The returned promise adopts the resolved value of the first resolved promise.
Rejection Handling:
Promise.race: If the promise that settles first is rejected, the returned promise will also reject with the same rejection reason.
Promise.any: If all input promises reject, the returned promise will reject with an aggregated error containing the reasons of all rejected promises. It only resolves if at least one promise resolves.
Use Cases:
Promise.race: Useful when you want to implement scenarios like a timeout mechanism where you want to respond to the first promise to complete, regardless of whether it succeeds or fails.
Promise.any: Useful when you want to handle the case where at least one promise out of multiple promises succeeds, and you're interested in the result of the first resolving promise.
Conclusion
So far, we have learned about Callback Hell and its solution as well. Then we explored promises in great detail and now we have learned about some of the important methods and their use-cases in real-life.
Follow me for more of such content:
LinkedIn: https://www.linkedin.com/in/shameeluddin/
Github: https://github.com/Shameel123
Posted on August 26, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.