Promise.all()
Continuing on with a look into JavaScript Promise
s, this week I'm writing about Promise.all()
. Promise.all()
is a method that takes an iterable of Promise
s as its sole argument, and returns a single Promise
that resolves to an array of the results of those input Promise
s.
This returned Promise
will either resolve when all of the provided input Promise
s have resolved or if the iterable provided contains no Promise
s. Otherwise the returned Promise
rejects immediately if any of the provided Promise
s reject or if a provided non-Promise
throws an error. In this case, it is rejected immediately.
Promise.all()
is useful for grouping together the results of multiple Promise
s. If you need multiple asynchronous tasks to complete before some other code execution continues, then you should use Promise.all()
.
const promise1 = Promise.resolve("first promise done");const promise2 = "second item done"; // not a Promise!const promise3 = new Promise((resolve, reject) => { setTimeout(() => resolve("third promise done"), 2000);});
Promise.all([promise1, promise2, promise3]).then((values) => { console.log(values);});// expected result (after two seconds):// ["first promise done", "second item done", "third promise done"]
In this example we have passed an array containing a few Promise
s to Promise.all()
. Note that promise2
contains a non-Promise
value. Promise.all()
simply ignores this value, but it still comes through in the returned Promise
array. After two seconds (since promise3
has a setTimeout
function that delays for two seconds), we get an array of our three results.
Syntax
Promise.all(iterable);
Parameters
iterable
- An iterable object such as an Array.
Return Value
Promise.all()
will return one of a few different things depending on the iterable that gets passed:
- If the iterable passed is empty, then
Promise.all()
will return an already resolvedPromise
. - If the iterable passed contains no
Promise
s, thenPromise.all()
will return an asynchronously resolvedPromise
. Note that Google Chrome 58 returns an already resolvedPromise
in this case. - In all other cases,
Promise.all()
will return a pendingPromise
. This returnedPromise
is then resolved or rejected asynchronously when all of thePromise
s in the given iterable have resolved, or if any of thePromise
s reject. The returned values will be in the order in which theirPromise
s were passed in the iterable, regardless of the order in which they were completed.
Fulfillment
The returned Promise
is fulfilled with an array containing all of the resolved values (including non-Promise
values) from the iterable passed as the argument.
If an empty iterable is passed, then the Promise
returned by Promise.all()
is fulfilled synchronously, and the resolved value is an empty array. For example:
const p = Promise.all([]); // An empty iterable is passed, this will resolve immediately.console.log(p);// expected result:// Promise { <state>: "fulfilled", <value>: Array[0] }
If a non-empty iterable is passed, and all of the Promise
s fulfill (or are not Promise
s), then the Promise
returned by Promise.all()
is fulfilled asynchronously. We have seen the first case in the example above, but let's look at an example where the iterable only has non-Promise
values:
const p = Promise.all(["first non-promise", 12345, true]);console.log(p);// expected result:// Promise { <state>: "pending" }
setTimeout(() => { console.log(p);});// expected result:// Promise: { <state>: "fulfilled", <value>: ["first non-promise", 12345, true] }
Rejection
If any of the Promises
in the passed iterable reject, Promise.all()
asynchronously rejects with the value of the Promise
that rejected, whether or not the other Promise
s have resolved.
Promise.all()
provides us with fail-fast behavior, meaning that the method rejects as soon as any of the passed Promise
s reject. For example:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => resolve("first promise done"), 1000);});const promise2 = new Promise((resolve, reject) => { setTimeout(() => resolve("second promise done"), 2000);});const promise3 = new Promise((resolve, reject) => { reject(new Error("reject!!"));});const promise4 = new Promise((resolve, reject) => { setTimeout(() => resolve("fourth promise done"), 4000);});
Promise.all([promise1, promise2, promise3, promise4]).then( (values) => console.log(values), (error) => console.error(error));// expected result (immediately): "reject!!"
Here we have four Promise
s, each of which use setTimeout()
functions to simulate some time-based code, except for the third Promise
, promise3
, which rejects immediately by throwing an Error
with the error message "reject!!". This rejection happens immediately, which makes Promise.all()
reject immediately with the "reject!!" error message. It doesn't wait for the other Promise
s to finish resolving.
However, it is possible to modify this behavior by handling rejections individually on each Promise
passed to Promise.all()
using the .catch()
instance method:
const promise1 = new Promise((resolve, reject) => { setTimeout(() => resolve("first promise done"), 1000);});const promise2 = new Promise((resolve, reject) => { setTimeout(() => resolve("second promise done"), 2000);});const promise3 = new Promise((resolve, reject) => { reject(new Error("reject!!"));});const promise4 = new Promise((resolve, reject) => { setTimeout(() => resolve("fourth promise done"), 4000);});
Promise.all([ promise1.catch((error) => error), promise2.catch((error) => error), promise3.catch((error) => error), promise4.catch((error) => error),]).then((values) => { console.log(values);});// expected result (after four seconds):// ["first promise done", "second promise done", Error: "reject!!", "fourth promise done"]
From MDN: The Promise.all()
method takes an iterable of Promise
s as an input, and returns a single Promise
that resolves to an array of the results of the input Promise
s. This returned Promise
will resolve when all of the input's Promise
s have resolved, or if the input iterable contains no Promise
s. It rejects immediately upon any of the input Promise
s rejecting or non-Promise
s throwing an error, and will reject with this first rejection message / error.
See more examples and further documentation here.