CodeBlanks Logo Icon CodeBlanks

Promise.race in depth

JavaScript course · Advanced · Lesson 74/100

Learn the timeout pattern and using the first result with Promise.race.

Promise.race in depth

Promise.race takes the first promise to settle from the ones it receives. The key point: settling means either fulfilling or rejecting. So if the first to settle is a rejection, race rejects too.

const r = await Promise.race([
  task,
  timeoutPromise
]);

This differs from Promise.any: any waits for a fulfilment, race accepts the first settle. That makes race ideal for timeout patterns.

The timeout pattern

To bound an operation in time, you use Promise.race. You race the operation promise against a rejecting timer promise. If the timer wins, the operation was too slow.

function withTimeout(task, ms) {
  const timer = new Promise((_, reject) =>
    setTimeout(() => reject('timeout'), ms)
  );
  return Promise.race([task, timer]);
}

This pattern keeps a network request from hanging forever and gives the user a quick response.

Exercise Write a fetchWithTimeout function

Write a function called fetchWithTimeout(url, ms). Inside, define a timeout promise using new Promise and setTimeout that rejects after ms milliseconds. Race fetch(url) and timeout with Promise.race and return the result. Capture the call fetchWithTimeout('/data', 500) into result with await and log it with console.log.

Show example solution
function fetchWithTimeout(url, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject('timeout'), ms)
  );
  return Promise.race([fetch(url), timeout]);
}
const result = await fetchWithTimeout('/data', 500);
console.log(result);

Test yourself

  1. Two promises race with Promise.race: one fulfils in 50ms, the other rejects in 30ms. What happens?

    • The 50ms fulfilled value is returned
    • The 30ms rejection is thrown
    • Both are returned
    • An AggregateError is thrown
    Show answer

    The 30ms rejection is thrown — Correct! race takes the first to settle; the 30ms reject arrives first, so it wins.

  2. Match the racing patterns

    race
    first settled
    any
    first fulfil
    allSettled
    waits for all
    timeout
    rejecting timer
  3. Timeout promise

    const timeout = new Promise((_, reject) =>
      setTimeout(() => reject('timeout'), ____));
    const result = await Promise.race([task, timeout]);
    Show answer
    const timeout = new Promise((_, reject) =>
      setTimeout(() => reject('timeout'), 500));
    const result = await Promise.race([task, timeout]);

All lessons in Advanced