Skip to content
aviral gupta

// I1.4 · ~33 min · Intermediate

Promise.all, allSettled, any and race

After this lesson you pick the right combinator for a group of promises: every result, every outcome, the first success, or the first to settle, which also gives you a timeout.

Lesson 4 of 6 in I1 Asynchronous JavaScript

You will be able to

  • Use Promise.all and Promise.allSettled and say what each gives when one input fails
  • Use Promise.any for the first success and read the AggregateError when every input fails
  • Use Promise.race for the first to settle, and build a timeout with it
  1. Warm-up · Activity 1 of 7

    Warm-up from lesson I1.1. b fails. What does this print? (fake settles after its ms.)

    try {
      console.log(await Promise.all([fake("a", 20), fake("b", 10, false)]));
    } catch (error) {
      console.log("caught:", error.message);
    }
  2. Predict · Activity 2 of 7

    Predict before you read on. The fastest mirror fails. What does Promise.any give?

    const file = await Promise.any([fake("mirror 1", 30), fake("mirror 2", 10, false), fake("mirror 3", 20)]);
    console.log(file);
  3. Practice · Activity 3 of 7

    Fill in the combinator that reports every outcome, so this prints “fulfilled a, rejected b failed”.

    const results = await Promise.____([fake("a", 20), fake("b", 10, false)]);
    console.log(results.map((r) => r.status + " " + (r.value ?? r.reason.message)).join(", "));
    await Promise.([fake("a", 20), fake("b", 10, false)]);
  4. Practice · Activity 4 of 7

    Match each combinator to when its promise settles.

  5. Practice · Activity 5 of 7

    A race against a 20 ms timeout. What does this print?

    const timeout = (ms) => new Promise((resolve, reject) => setTimeout(() => reject(new Error("timed out")), ms));
    
    try {
      console.log(await Promise.race([fake("report", 50), timeout(20)]));
    } catch (error) {
      console.log("error:", error.message);
    }
  6. Brain teaser · Activity 6 of 7

    Brain teaser. Every input fails. What does this print?

    try {
      await Promise.any([
        Promise.reject(new Error("first")),
        Promise.reject(new Error("second"))
      ]);
    } catch (error) {
      console.log(error.name, error.errors.length, error.errors[1].message);
    }
  7. Apply · Activity 7 of 7

    Mini-task: weather from three sources. Write source(name, ms, ok) that settles after ms with "name: 21 °C" or rejects with "name down". Then use each combinator once: all when every source must answer, allSettled for a report of each outcome, any for the fastest working source while the fastest one fails, and race against a 15 ms timeout. Print each result.

    Check your work against this list

Build it yourself

Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.

Worked example

Four combinators, side by side

fake() settles after a delay, fulfilled with its name or rejected. Each combinator gets a group of these. all gives every value in input order, or fails on b. allSettled reports both outcomes. any finds the first mirror that works and, when all fail, throws an AggregateError. race takes the first to settle, and with a rejecting timer that is a timeout.

main.js

// fake(name, ms, ok) settles after ms milliseconds: fulfilled with name, or rejected.
const fake = (name, ms, ok = true) =>
  new Promise((resolve, reject) =>
    setTimeout(() => (ok ? resolve(name) : reject(new Error(`${name} failed`))), ms)
  );

console.log("all:", await Promise.all([fake("a", 30), fake("b", 10)]));
try {
  await Promise.all([fake("a", 30), fake("b", 10, false)]);
} catch (error) {
  console.log("all failed:", error.message);
}

const settled = await Promise.allSettled([fake("a", 30), fake("b", 10, false)]);
console.log("allSettled:", settled.map((r) => r.status));

console.log("any:", await Promise.any([fake("mirror 1", 30), fake("mirror 2", 10, false), fake("mirror 3", 20)]));
try {
  await Promise.any([fake("x", 10, false), fake("y", 20, false)]);
} catch (error) {
  console.log("any failed:", error.name, error.errors.map((e) => e.message));
}

const timeout = (ms) =>
  new Promise((resolve, reject) => setTimeout(() => reject(new Error(`timed out after ${ms} ms`)), ms));
console.log("race:", await Promise.race([fake("quick", 10), timeout(50)]));
try {
  await Promise.race([fake("slow", 80), timeout(20)]);
} catch (error) {
  console.log("race failed:", error.message);
}

Run it with

node main.js

Output

all: [ 'a', 'b' ]
all failed: b failed
allSettled: [ 'fulfilled', 'rejected' ]
any: mirror 3
any failed: AggregateError [ 'x failed', 'y failed' ]
race: quick
race failed: timed out after 20 ms
  • all keeps input order: a first, although b finished first.
  • any skipped mirror 2, which failed first, and took mirror 3.
  • The AggregateError’s errors array keeps input order: x, then y.
  • The slow promise in the last race still ran to the end; race only stopped waiting for it.
Change it and run it

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Exercises

Exercise 1 of 2

A timeout that rejects

withTimeout(promise, ms) should settle like promise when it settles within ms milliseconds, and otherwise reject with an Error whose message is timed out after <ms> ms. The starter races promise against a timer that fulfils, so a slow promise gives undefined instead of an error. Make the timer reject.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    Run the tests: the slow case gives undefined. What does the timer promise settle with?

  2. Hint 2

    race takes on the first input to settle, fulfilled or rejected. The timer must reject to make race reject.

  3. Hint 3

    new Promise((resolve, reject) => setTimeout(() => reject(new Error(`timed out after ${ms} ms`)), ms))

Show a solution

One way to solve it. Yours can look different and still pass the checks.

export function withTimeout(promise, ms) {
  const timer = new Promise((resolve, reject) =>
    setTimeout(() => reject(new Error(`timed out after ${ms} ms`)), ms)
  );
  return Promise.race([promise, timer]);
}
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

export function withTimeout(promise, ms) {
  const timer = new Promise((resolve) => setTimeout(resolve, ms));
  return Promise.race([promise, timer]);
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {withTimeout} from './main.js';

const later = (value, ms) => new Promise((resolve) => setTimeout(() => resolve(value), ms));

test('A fast promise gives its value', async () => {
  const got = await withTimeout(later('report', 5), 50);
  assert.equal(got, 'report', `withTimeout gave ${got}`);
});

test('A slow promise rejects with timed out after 20 ms', async () => {
  await assert.rejects(withTimeout(later('report', 60), 20), {message: 'timed out after 20 ms'}, 'withTimeout should reject when the promise is too slow');
});

test('A fast rejection passes through unchanged', async () => {
  await assert.rejects(withTimeout(Promise.reject(new Error('offline')), 50), {message: 'offline'}, 'withTimeout should reject with the promise\'s own error');
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Exercise 2 of 2

The first mirror that works

firstAvailable(mirrors) gets an array of functions; each starts a download and returns a promise. It should start them all and return the first successful result, even if a faster mirror fails. If every mirror fails, it rejects with an Error whose message is no mirror available. The starter uses race, so a fast failure wins. Use the right combinator.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    Run the tests: the failing us mirror wins the race. Which combinator ignores rejections?

  2. Hint 2

    Promise.any fulfils with the first success and rejects only when every input has rejected.

  3. Hint 3

    Wrap await Promise.any(…) in try/catch and throw new Error("no mirror available") in the catch.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

export async function firstAvailable(mirrors) {
  try {
    return await Promise.any(mirrors.map((start) => start()));
  } catch {
    throw new Error("no mirror available");
  }
}
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

export async function firstAvailable(mirrors) {
  return Promise.race(mirrors.map((start) => start()));
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {firstAvailable} from './main.js';

const mirror = (name, ms, ok = true) => () =>
  new Promise((resolve, reject) => setTimeout(() => (ok ? resolve(name) : reject(new Error(name + ' down'))), ms));

test('The fastest working mirror wins', async () => {
  const got = await firstAvailable([mirror('eu', 30), mirror('us', 10)]);
  assert.equal(got, 'us', `firstAvailable gave ${got}`);
});

test('A faster mirror that fails is skipped', async () => {
  const got = await firstAvailable([mirror('eu', 30), mirror('us', 5, false)]);
  assert.equal(got, 'eu', `firstAvailable gave ${got}`);
});

test('When every mirror fails, it rejects with no mirror available', async () => {
  await assert.rejects(firstAvailable([mirror('eu', 10, false), mirror('us', 5, false)]), {message: 'no mirror available'}, 'firstAvailable should reject with no mirror available');
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Common mistakes

Promises passed one by one instead of in an array

const a = Promise.resolve("a");
const b = Promise.resolve("b");
const values = await Promise.all(a, b);
console.log(values);

What Node.js prints

TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))

Why, and the fix

Every combinator takes one iterable, usually an array, as its only argument. Promise.all(a, b) treats the promise a as that iterable and ignores b, and a promise cannot be iterated. Wrap the inputs in square brackets: await Promise.all([a, b]).

Passing the functions instead of calling them

const loadA = async () => "a";
const loadB = async () => "b";
const [first] = await Promise.all([loadA, loadB]);
console.log(first.toUpperCase());

What Node.js prints

TypeError: first.toUpperCase is not a function

Why, and the fix

A value in the array that is not a promise is passed through as it is. Here those values are the functions themselves, so first is the function loadA, and nothing was loaded at all. Call each function so the array holds running promises: Promise.all([loadA(), loadB()]).

Promise.any with no catch when everything fails

const down = (name) => Promise.reject(new Error(`${name} down`));
const file = await Promise.any([down("eu"), down("us")]);
console.log(file);

What Node.js prints

AggregateError: All promises were rejected

Why, and the fix

When every input rejects, any rejects with an AggregateError, and nothing here catches it, so the program stops. The message only says that all were rejected; the reasons are in error.errors. Await it inside try/catch and read error.errors for each mirror’s reason.

JavaScript in the browser: your browser’s own engine, in a sandboxed worker. Syntax errors are located with acorn 8.18.0, MIT. Licence and source

Exit ticket

5 questions, no hints. Score 80% or more to complete the lesson.

Finish every activity above to unlock the exit ticket.

Report a problem

Spotted something wrong or unclear? Say what, and it will be checked and fixed.

#

At least 20 characters.

Only if you want a reply.

Key ideas

all and allSettled: the whole group

Promise.all([p1, p2]) fulfils with an array of values in input order, whatever order they finished in. It rejects as soon as one input rejects, with that first reason, and you lose the other results. Promise.allSettled never rejects: it waits for every input and gives one object per input, {status: "fulfilled", value} or {status: "rejected", reason}. With an empty array, both fulfil at once with []. Use all when you need every result; allSettled when you must report each outcome.

any: the first success

Promise.any fulfils with the value of the first input to fulfil, and ignores rejections until then, so a fast failure does not stop it. Only if every input rejects does it reject, with an AggregateError: its message in V8 is All promises were rejected, and its errors property holds every reason, in input order. An empty array rejects at once, because nothing can succeed. Use any for redundant sources, such as several mirrors of one file.

race: the first to settle

Promise.race settles like whichever input settles first, fulfilled or rejected. Its classic use is a timeout: race the work against a promise that rejects after ms milliseconds. Whichever comes first wins. None of the four combinators cancels anything: the losing timer still fires and the slow work still runs to the end; real cancellation is AbortController, in lesson I6.3. An empty array makes race pending forever. Every combinator expects one iterable, such as an array, of promises that are already running.

Sources

Last reviewed October 5, 2026