Skip to content

Intermediate · Asynchronous JavaScript · topic 39 of 61 · 25 min

Promise.all, allSettled, race and any

Explanation

Four helpers combine many promises. Promise.all waits for all and fails fast on the first error; allSettled waits for all and reports each outcome; race settles with whichever settles first (useful for timeouts); any fulfils with the first success. With these you can build timeouts, retries and concurrency limits.

Why combine promises?

Real apps often run several async tasks: load five widgets, send 100 SMS, ask three servers for the fastest answer. The Promise class has four static methods for these patterns. Each takes an iterable of promises and returns ONE promise.

MethodFulfils whenRejects whenUse for
Promise.allall fulfil (array of values, in input order)any one rejects (fail fast)Everything is needed
Promise.allSettledall settle (never rejects)—Report each success/failure
Promise.racethe first to settle fulfilsthe first to settle rejectsTimeouts
Promise.anythe first to fulfilall reject (AggregateError)Fastest working mirror

Promise.all

javascript
const [user, orders] = await Promise.all([getUser(7), getOrders(7)]);
// results come in INPUT order, not finishing order

If one promise rejects, Promise.all rejects immediately with that error. The other operations keep running in the background (promises cannot be cancelled), but their results are ignored.

Promise.allSettled

javascript
const results = await Promise.allSettled([sendSms('A'), sendSms('B'), sendSms('C')]);
// [{ status: 'fulfilled', value: … }, { status: 'rejected', reason: Error }, …]
const failed = results.filter((r) => r.status === 'rejected').length;
console.log(`${failed} SMS failed`);

Timeouts with race

javascript
function withTimeout(promise, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error(`Timed out after ${ms} ms`)), ms)
  );
  return Promise.race([promise, timeout]);
}
// await withTimeout(fetchFare(), 3000);

Retry with backoff

Networks fail now and then. A retry tries again a few times, waiting a little longer each time (backoff), so a struggling server is not flooded.

javascript
async function retry(task, attempts = 3, delayMs = 200) {
  for (let i = 1; i <= attempts; i++) {
    try {
      return await task();
    } catch (err) {
      if (i === attempts) throw err;
      await new Promise((r) => setTimeout(r, delayMs * 2 ** (i - 1))); // 200, 400, 800…
    }
  }
}

Limiting concurrency

Promise.all on 10,000 requests starts them all at once, which can overload a server or hit rate limits. A small pool runs at most N at a time.

javascript
async function mapWithLimit(items, limit, worker) {
  const results = new Array(items.length);
  let next = 0;
  async function runner() {
    while (next < items.length) {
      const i = next++;
      results[i] = await worker(items[i]);
    }
  }
  await Promise.all(Array.from({ length: Math.min(limit, items.length) }, runner));
  return results;
}
Careful: Only retry operations that are safe to repeat. Retrying "charge the card" after a timeout can charge the customer twice, because the first attempt may have succeeded. Payment APIs use idempotency keys (a unique id per payment) so that a repeated request is recognised and not charged again.
Think of it like this: Promise.all is a group trip that leaves only when everyone has arrived, and is cancelled if anyone drops out. allSettled is the class teacher taking attendance: present or absent, everyone is noted. race is the first auto-rickshaw that stops for you. any is calling three taxi services and taking the first one that says yes.
Tip: In a timeout with race, the slow operation still runs in the background. To really stop a fetch, use an AbortController (last topic of this module).

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Promise.all, allSettled, race and any · 1/6

all · allSettled · race · any

In this lesson you will combine many promises with four helpers.

Prefer a video by a teacher? Find free videos on “javascript promise.all allSettled race any explained” on YouTube ↗

In real life: Sending festival offers by SMS

A retail chain sends a Diwali offer to 20,000 customers through an SMS provider that allows 10 requests at a time. The team uses a concurrency limit of 10, retries each failed send twice, and uses allSettled-style reporting to list the numbers that still failed for a later attempt.

javascript
const sendSms = async (n) => { if (n.endsWith('3')) throw new Error('bad number'); return 'ok'; };
const numbers = ['9811111111', '9822222223', '9833333333'];
Promise.allSettled(numbers.map(sendSms)).then((res) => {
  const failed = numbers.filter((_, i) => res[i].status === 'rejected');
  console.log(failed); // ['9822222223', '9833333333']
});

Practice (0/3 done)

Task 1 · Code · Javascript

Write withTimeout(promise, ms) that returns a promise which settles like the given promise, but rejects with an Error "Timed out" if it takes longer than ms.

Task 2 · Code · Javascript

Write summarise(tasks) where tasks is an array of functions returning promises. Run them all and return { ok, failed } counts, never rejecting. Use Promise.allSettled.

Task 3 · Code · Javascript

Write retry(task, attempts) that calls the async function task up to attempts times until it succeeds, returning its value. If every attempt fails, reject with the LAST error. (No delay needed.)

Quick quiz

Question 1

1.Promise.all([p1, p2]) where p2 rejects. What happens?

Question 2

2.Which never rejects?

Question 3

3.In what order does Promise.all return values?

Question 4

4.Why can retrying a payment be dangerous?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Promise.all([p1, p2]) where p2 rejects. What happens?

Answer: It rejects with p2's error

Promise.all fails fast on the first rejection.

Which never rejects?

Answer: Promise.allSettled

allSettled always fulfils with a report for each promise.

In what order does Promise.all return values?

Answer: Input order

Results match the order of the input promises.

Why can retrying a payment be dangerous?

Answer: The first attempt may have succeeded, causing a double charge

Only retry idempotent operations, or use idempotency keys.

Three independent requests each take about 1 second. How long does await Promise.all([a(), b(), c()]) take?Related

Answer: About 1 second

Promise.all starts them together, so the total is about the slowest one. Awaiting them one by one would take about 3 seconds.

From async/await and error handling

Promise.resolve(2).then((n) => n * 3).then((n) => n + 1) fulfils with…Related

Answer: 7

2 × 3 = 6, then 6 + 1 = 7.

From Promises

Which request is safe to retry automatically after a network error?Related

Answer: GET /api/notes

Reading notes again changes nothing. A POST may already have worked, so repeating it can create duplicates or double payments.

From Loading, errors and slow networks

How do you handle a rejected await?Related

Answer: try/catch around the await

A rejection is thrown at the await, so catch it.

From async and await

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 2 more topics in “Asynchronous JavaScript” before its exam: The event loop, fetch: talking to servers.
  2. Module 8 exam: Asynchronous JavaScript · 12 questions · 25 min, without help. 6 topics of this module still to finish first.
  3. Then the next module, TypeScript basics. 61 topics left in the course before the final exam.

← Previous: async and await