Compile Ready
Module 9 · Promises

Promise.race

Intermediate12m read9m practice21m total
PromisesCombinatorsRaceTimeouts

Introduction

Promise.race(iterable) settles as soon as the first input settles, whether that input fulfils or rejects. It is the first-signal-wins combinator, commonly used for timeouts, fallback signals, and taking the earliest result when both success and failure should be decisive.

Why This Matters

race is a common source of wrong answers because candidates treat it like fastest success. It is not. A fast rejection rejects the race. A plain value can win before timer-backed promises. The losers are not cancelled automatically.

Theory

Exact semantics

Promise.race accepts an iterable of values, promises, or thenables. It settles with the outcome of the first input that settles. If the first settled input fulfils, the race fulfils with that value. If the first settled input rejects, the race rejects with that reason.

Plain values are treated as already fulfilled, so a plain value usually wins over promises that settle in future timer turns. If several already-settled promises are observed together, their reactions are queued in iteration order, so the earliest observed reaction wins.

For an empty iterable, there is no input that can settle, so Promise.race([]) returns a promise that remains pending forever.

Like all promise combinators, race does not cancel losers. A timeout race can reject quickly while the original operation continues unless the underlying API supports cancellation.

Combinator comparison

CombinatorFulfils whenRejects whenResult shapeTypical use
Promise.allEvery input fulfilsFirst input rejectsArray of values in input orderAll-or-nothing parallel work
Promise.anyFirst input fulfilsEvery input rejectsFirst fulfilled value or AggregateErrorRedundant sources, fastest success
Promise.allSettledEvery input settlesNever because of input rejectionArray of status objects in input orderPartial success reporting
Promise.raceFirst input fulfils if it settles firstFirst input rejects if it settles firstFirst settled value or reasonTimeouts, first signal wins

Timeout pattern

The classic pattern races real work against a promise that rejects after a delay. This limits how long the caller waits, but it does not stop the real work by itself. In production, pair the timeout with a cancellation mechanism when possible.

Race vs any

Use race when the earliest signal should decide the outcome, including failure. Use any when failures are tolerable and you want the first success.

Visual Diagrams

First settlement wins
A pending -------- fulfils later
B pending ---- rejects first ---- Promise.race rejects with B reason
C pending -------- fulfils later

The first settled input decides the combined promise.

Race observes settlement, not success.

Timeout race shape
real work promise ---------------- maybe fulfils later
timeout promise ---- rejects first
        |
        v
Promise.race rejects with timeout reason

The real work is still running unless cancelled separately.

A timeout race limits waiting; it does not automatically cancel work.

Code Examples

Build a timeout with Promise.race

The timeout rejects the race if the operation takes too long. Cancellation of the operation is separate.

Loading…

Plain values can win the race

Values are normalised through promise resolution, so a non-promise input can settle the race before async work.

Loading…

Playground

Loading editor…
Console

Press Run to execute the code and see output here.

Output Prediction

Predict the output #1

javascript
1const slow = new Promise(function (resolve) {
2 setTimeout(function () {
3 console.log('slow done');
4 resolve('slow');
5 }, 20);
6});
7
8const fast = new Promise(function (resolve, reject) {
9 setTimeout(function () {
10 console.log('fast failed');
11 reject('fast');
12 }, 10);
13});
14
15Promise.race([slow, fast])
16 .then(function (value) {
17 console.log('win ' + value);
18 })
19 .catch(function (reason) {
20 console.log('lose ' + reason);
21 });
22
23console.log('sync');

Predict the output #2

javascript
1Promise.race([
2 new Promise(function (resolve) {
3 setTimeout(function () {
4 resolve('timer');
5 }, 0);
6 }),
7 'plain',
8]).then(function (value) {
9 console.log(value);
10});
11
12console.log('sync');

Coding Exercises

Implement a mini Promise.race

Medium

Implement promiseRace(iterable): accept values or promises and settle with the first input to settle, whether fulfilled or rejected. Empty input should leave the returned promise pending.

Interview Questions

1Explain `Promise.race` and a common use case.

Promise.race returns a promise that settles with the first input to settle, whether fulfilled or rejected. A common use case is racing an operation against a timeout promise. If the timeout rejects first, the caller stops waiting, but the original operation is not automatically cancelled.

Asked at:NetflixGoogleMicrosoft

Follow-ups

  • How is it different from `Promise.any`?
  • What happens with `Promise.race([])`?
2Does `Promise.race` cancel the losing promises?

No. Promise.race only settles the combined promise with the first settlement. Losing promises continue to run and may still produce side effects. If cancellation matters, the underlying operation must support cancellation and you must trigger it explicitly.

Quiz

1. Which input wins `Promise.race`?

2. What does `Promise.race([])` do?

Summary

  • `Promise.race` settles with the first input to settle, fulfilled or rejected.
  • A fast rejection rejects the race; use `Promise.any` when you want fastest success instead.
  • Plain values can win because inputs are normalised through promise resolution.
  • `race` does not cancel losers, and `Promise.race([])` stays pending forever.

Cheat Sheet

Use when: first signal wins.

Fulfil: first settled input fulfils.

Reject: first settled input rejects.

Empty: pending forever.

Timeout pattern: Promise.race([work, timeout]).

Caveat: losers continue unless cancelled separately.