Promise.all()
Promise.all() is a static method that takes an iterable of promises and returns a single Promise that resolves to an array of results. It is useful when you need to coordinate multiple asynchronous operations that all must complete before proceeding.
Syntax
Promise.all(iterable)
Parameters
| Parameter | Type | Description |
|---|---|---|
iterable | Iterable | An iterable object (such as an Array) containing Promise objects or other values |
Return Value
Returns a Promise that:
- If all input promises resolve, resolves with an array of results in input order
- If any input promise rejects, rejects immediately with that reason (fails fast)
- Non-promise values in the iterable pass through to the result array unchanged
Examples
Basic Usage
const promise1 = Promise.resolve(3);
const promise2 = Promise.resolve(42);
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([promise1, promise2, promise3])
.then((results) => {
console.log(results); // [3, 42, 'foo']
});
The example above shows static promises, but the real value of Promise.all() emerges when each promise is backed by a network request or file read. The next example demonstrates fetching multiple API endpoints in parallel — each user loads independently, and the results arrive together once every request completes.
Real-world: fetching multiple APIs
async function fetchUserData(userIds) {
const requests = userIds.map(id =>
fetch(`/api/users/${id}`).then(r => r.json())
);
// Wait for all users to load
const users = await Promise.all(requests);
return users;
}
fetchUserData([1, 2, 3]).then(users => {
console.log(`Loaded ${users.length} users`);
});
Not every element in the iterable needs to be a native promise. Promise.all() is forgiving — plain values pass through to the result array in their original position. This makes it convenient when some data is already available synchronously and the rest needs to be fetched.
Handling mixed values
// Non-promise values are passed through
const mixed = Promise.all([1, 2, Promise.resolve(3)]);
mixed.then(console.log); // [1, 2, 3]
The fail-fast behavior is the sharpest edge of Promise.all() — a single rejection aborts the whole group without waiting for the others. Understanding this is essential before you choose Promise.all() over its alternatives. The following example demonstrates exactly how a rejection takes down the entire group.
Error Handling
const promises = [
Promise.resolve('success'),
Promise.reject(new Error('failed'))
];
Promise.all(promises)
.then(results => console.log(results))
.catch(error => {
// This runs because one promise rejected
console.error('At least one failed:', error.message);
});
Three behaviors define how Promise.all() operates, and each one matters when you are choosing between Promise.all(), Promise.allSettled(), and Promise.race().
Key Behaviors
Promise.all() fails fast: if any promise rejects, the entire result rejects immediately with that reason. Results always maintain the same order as the input iterable, regardless of which promise settles first. An empty iterable resolves synchronously with an empty array.
Common Pitfalls
A common mistake is not handling rejection properly:
// DANGEROUS: This will reject if ANY promise rejects
const results = await Promise.all(requests);
// SAFER: Use Promise.allSettled if you need all results regardless of failures
const results = await Promise.allSettled(requests);
The choice between Promise.all() and Promise.allSettled() comes down to whether partial success is meaningful. If every promise must resolve for the result to be useful, stick with Promise.all(). If individual items can succeed or fail independently, allSettled gives you the full picture without losing data from the successes.
Promise.all() vs Promise.allSettled()
Promise.all() fails fast — the first rejection rejects the whole result. Promise.allSettled() waits for every promise to complete, then returns an array of outcome objects regardless of success or failure:
const promises = [
Promise.resolve("ok"),
Promise.reject(new Error("failed")),
Promise.resolve("also ok")
];
// Promise.all — rejects immediately on first failure
await Promise.all(promises);
// throws Error: "failed"
// Promise.allSettled — waits for all, reports each outcome
const results = await Promise.allSettled(promises);
// [
// { status: 'fulfilled', value: 'ok' },
// { status: 'rejected', reason: Error: 'failed' },
// { status: 'fulfilled', value: 'also ok' }
// ]
Use Promise.allSettled() when you need all results regardless of partial failures — for example, batch-processing items where a single failure should not abort the whole batch.
When Promise.all() is the better fit
Promise.all() is ideal when the whole operation depends on every promise succeeding. Loading a page that needs a user, a settings object, and a feature list is a good example: if any one piece fails, there is usually no point in continuing with partial data. The fail-fast behavior is not a drawback in that case; it is a signal that the combined operation should be treated as one unit.
Working with partial failures
If some results can fail independently, Promise.all() is usually too strict. In that case, Promise.allSettled() or a per-item catch() strategy gives you more control over the outcome. That choice is less about syntax and more about product behavior: do you want one failure to stop everything, or do you want to present the successes you already have? Writing that intent explicitly makes async code easier to maintain.
Result order is guaranteed
The resolved array always matches the input order, regardless of which promises resolve first:
const p1 = new Promise(resolve => setTimeout(resolve, 300, 'slow'));
const p2 = new Promise(resolve => setTimeout(resolve, 100, 'fast'));
const p3 = Promise.resolve('instant');
const [a, b, c] = await Promise.all([p1, p2, p3]);
// a = 'slow', b = 'fast', c = 'instant'
// Order matches input, not resolution order
This predictable ordering is what makes Promise.all() safe to use with destructuring.
One edge case worth knowing: an empty iterable resolves immediately rather than waiting. This is consistent with the mathematical identity of the operation — combining zero promises should give you an empty result with no delay.
Empty iterable returns immediately
Promise.all([]) resolves synchronously with an empty array. This is the correct identity for a “wait for all” operation on zero items:
const result = await Promise.all([]);
console.log(result); // []
See Also
Promise.allSettled()— Wait for all, get every outcomePromise.race()— Resolves when the first promise settlesPromise— The Promise object overview