Promise.all()

The standard way to run several async operations at once. Its fail-fast behaviour is the right default and the source of its two traps: you lose the successful results, and the other operations keep running.

Promise static methodES2015Live demo
Common call
await Promise.all(urls.map(fetch))
Returns
a Promise for an array, in input order
Replaces
sequential awaits in a loop
Watch out
one rejection discards every other RESULT
Promise.all(iterableiterable — Any iterable, usually an array. Non-promise values are passed through as if already resolved, so a mixed array works.type: iterable · required)
→ Promise<Array>

Demo

Live evaluation
Try:
Inputs
jsonstringJSON list of [outcome, value, ms]
Output
await Promise.all(JSON.parse('[["ok",1,30],["ok",2,10]]').map(([k, v, ms]) => new Promise((res, rej) => setTimeout(() => k === 'ok' ? res(v) : rej(new Error(v)), ms))))
Pending…

Each input is [outcome, value, delay in ms]: 'ok' fulfils with the value, anything else rejects with an Error carrying it. The first case finishes the second input first, yet the result is [1, 2] — input order, which is what makes destructuring safe. The third case is the fail-fast rule: the rejection after 10ms settles the whole thing, and the success still pending at 50ms is simply discarded — not cancelled, just ignored. An empty list resolves immediately with an empty array.

Parameters

NameTypeRequiredDescription
iterableiterableyesAny iterable, usually an array. Non-promise values are passed through as if already resolved, so a mixed array works.

Return value

Promise<Array> — A Promise for an array of results in the ORDER OF THE INPUT, not the order they finished. Rejects as soon as any input rejects, with that first reason.

Common patterns

Run requests concurrently
The canonical use — map to promises, then await once.
const [user, posts] = await Promise.all([
  fetchUser(id),
  fetchPosts(id),
]);
Start before you await
The promises must already be running.
const a = fetchA();
const b = fetchB();
const [ra, rb] = await Promise.all([a, b]);
Keep partial results
allSettled when one failure should not lose the rest.
const results = await Promise.allSettled(tasks);

Examples

1. Results in input order
await Promise.all([delay(20, 1), Promise.resolve(2)])
Returns
[1, 2]
2. Non-promises pass through
await Promise.all([1, 2])
Returns
[1, 2]
3. Empty array resolves at once
await Promise.all([])
Returns
[]
4. First rejection wins
await Promise.all([Promise.resolve(1), Promise.reject(new Error("boom"))])
Returns
throws Error: boom
5. Successes are discarded
try { await Promise.all([Promise.resolve(1), Promise.reject(e)]); } catch { }
Returns
the 1 is unreachable
6. The others keep running
the slow task still completes after the rejection
Returns
true

Pitfalls

1. One rejection throws away every successful result
The rejection reason is all you get — the results that DID arrive are unreachable. For a dashboard where three of four panels loaded, that is the wrong trade, and allSettled is the method you wanted.
All or nothing
await Promise.all([ok1, ok2, failing])
throws; ok1 and ok2 are lost
Keep what worked
const rs = await Promise.allSettled([ok1, ok2, failing]);
rs.filter(r => r.status === "fulfilled")
two results
2. Rejecting does not cancel the other operations
There is no cancellation in the Promise model. The remaining requests continue, their results are ignored, and any rejection among them may surface as an unhandled rejection. Use AbortController if you need the work to actually stop.
Still running
await Promise.all([failing, slowFetch])
slowFetch completes regardless
Abort them
const c = new AbortController();
// pass c.signal to each fetch, then c.abort()
requests cancelled
3. Awaiting inside a loop is not concurrent
The commonest performance mistake in async JavaScript. A for loop with an await inside runs one request at a time; Promise.all over a mapped array runs them together. The difference is n × latency versus one latency.
Sequential
for (const u of urls) results.push(await fetch(u));
sum of all latencies
Concurrent
const results = await Promise.all(urls.map(u => fetch(u)));
the slowest latency
4. Creating the promises inside the array is what starts them
Promise.all does not start anything — it only waits. Passing an array of FUNCTIONS waits for nothing useful, because a function is not a promise and is passed straight through as a value.
Functions, not promises
await Promise.all([() => fetchA(), () => fetchB()])
an array of the two functions
Call them
await Promise.all([fetchA(), fetchB()])
the two results

When to use

Use it
  • Several independent async operations that must all succeed
  • Fetching data for one view from multiple endpoints
  • Anywhere a loop currently awaits one item at a time
Reach for something else
  • Partial success is acceptable → allSettled
  • You want the first result only → race, or any
  • The operations depend on each other → sequential awaits are correct
  • You need to cancel on failure → AbortController alongside

Notes

Complexity
O(n) to attach handlers; wall-clock time is the slowest input
Return
A new Promise; the inputs are not modified
CPython impl
V8: Builtins-promise-all
Memory
Holds every result until all settle
Thread-safe
Single-threaded; concurrency here is I/O overlap, not parallelism

FAQ

It runs them CONCURRENTLY, which for I/O is what matters — the requests overlap. JavaScript is single-threaded, so nothing is parallel in the CPU sense. The promises must also already be in flight; Promise.all only waits.

History

ES2015
Promise.all and Promise.race added with the Promise constructor.
ES2020
allSettled and any added, covering the cases all cannot express.