Three independent network calls, run one after the other, cost the sum of their durations. Started together, they cost the slowest one.
That is exactly the gain Promise.all delivers, and the reason it shows up in nearly every page that loads data.
Definition
Promise.all(list) takes a list of promises and returns a single promise, fulfilled with the array of every value once the last one lands, rejected the moment any one of them fails.
const later = (v, ms) => new Promise((r) => setTimeout(() => r(v), ms));
async function load() {
const [profile, invoices] = await Promise.all([
later({ name: "Chloe" }, 120),
later([{ amount: 19 }], 80),
]);
console.log(profile.name, invoices.length); // Chloe 1
}
load();Destructuring of the result is the usual form. Both calls left at the same time, so the total wait is that of the longer one, not the sum of the two.
The order is the list's, not the answers'
A point often misread: the array handed back follows the order in which the promises were supplied. The fastest one does not land in first position, it stays where it was placed.
That guarantee makes the result usable straight away, with no need to work out which value belongs to which call. It also lets the list be built with Array.map() over a collection.
const ids = [1, 2, 3];
async function readAll() {
const rows = await Promise.all(
ids.map((id) => later("row " + id, 10 * id))
);
console.log(rows); // [ 'row 1', 'row 2', 'row 3' ]
}
readAll();The first failure wins
A single rejection breaks the overall promise there and then, without waiting for the others. The remaining promises are not canceled for all that: they keep running, and their results are simply thrown away.
| Method | Behavior on failure |
|---|---|
Promise.all | Rejects immediately, values already obtained are lost |
Promise.allSettled | Never rejects, hands back the outcome of each one |
Those two rows are enough to choose between them: all for data that is all indispensable, allSettled for a dashboard where one broken tile must not empty the page.
A rejected promise whose failure nobody reads, because all already failed elsewhere, still counts as an unhandled rejection to the engine. Under Node.js that can stop the process, which is one more argument for allSettled when the calls are genuinely independent.
Frequently asked questions
What does Promise.all([]) hand back?
A promise fulfilled with an empty array, settled immediately. That is the desirable behavior: a loop producing no calls at all needs no special case, and the chain carries on without an extra condition.
Can it hold things other than promises?
Yes. Any plain value sitting in the list is converted into an already-fulfilled promise and comes back out unchanged. Mixing a cached value and a network call in the same list therefore works with no special care.
Is there a limit to how many promises it takes?
None in the language, but plenty on the server side. Firing a thousand requests at once saturates the connection and often trips a rate limit. Past a few dozen calls, cut the list into batches handled one after another, or run them through a small queue.