The `Promise.all()` Function in JavaScript
The Promise.all()
function converts an array of
promises into a single promise that fulfills when all the promises
in the original array fulfill.
Here's an example of using Promise.all()
to wrap an array of promises:
// `p1` is immediately fulfilled with value `1`
const p1 = Promise.resolve(1);
// `p2` will be fulfilled with value `2` after 100ms
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 100));
const pAll = Promise.all([p1, p2]);
pAll instanceof Promise; // true
const arr = await pAll;
Array.isArray(arr); // true
arr[0]; // 1
arr[1]; // 2
Parallel Execution of Async Functions
When used with async functions, Promise.all()
lets you execute code in parallel. Pass an array of async
function calls to Promise.all()
, and
JavaScript will execute the async functions in parallel.
Suppose you have two async functions getName()
and getAge()
. Here's
how you can use Promise.all()
to execute them in parallel:
async function getName() {
await new Promise(resolve => setTimeout(resolve, 200));
return 'Jean-Luc Picard';
}
async function getAge() {
await new Promise(resolve => setTimeout(resolve, 200));
return 59;
}
const start = Date.now();
const [name, age] = await Promise.all([getName(), getAge()]);
const end = Date.now();
name; // 'Jean-Luc Picard'
age; // 59
end - start; // Approximately 200
Error Case
If one of the promises rejects, the promise returned by Promise.all()
rejects immediately with the same error.
const success = new Promise(resolve => setTimeout(() => resolve('OK'), 100));
const fail = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Oops')), 100);
});
try {
await Promise.all([success, fail]);
} catch (err) {
err.message; // 'Oops'
}
Note that, since promises are not cancellable, each individual promise
continues execution, even if one of them errors out. If you pass an
array of async functions and one of the async functions throws an
error, Promise.all()
will reject immediately with that error.
But the other functions will continue executing.
let finished = false;
const success = async function() {
await new Promise(resolve => setTimeout(resolve, 100));
finished = true;
return 'OK';
}
const fail = async function() {
await new Promise(resolve => setTimeout(resolve, 10));
throw new Error('Oops');
}
try {
await Promise.all([success(), fail()]);
} catch (err) {
err.message; // 'Oops'
// `Promise.all()` fails fast because `fail()` threw an
// error, but `success()` is still running.
finished; // false
// If you wait, `success()` will set `finished`
await new Promise(resolve => setTimeout(resolve, 100));
finished; // true
}
Getting Fancy with Generators
The Promise.all()
function doesn't limit you to arrays, the first parameter
can be any JavaScript iterable. Arrays are iterables,
and so are generator functions. Which means you can pass in a generator
that yields promises, and Promise.all()
will bundle all the yielded
promises into a single promise.
const generatorFn = function*() {
for (let i = 1; i <= 5; ++i) {
yield Promise.resolve(i);
}
}
const arr = await Promise.all(generatorFn());
arr; // [1, 2, 3, 4, 5]