jsguides

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

ParameterTypeDescription
iterableIterableAn 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