Promise.race in depth
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
-
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.
-
Match the racing patterns
- race
- first settled
- any
- first fulfil
- allSettled
- waits for all
- timeout
- rejecting timer
-
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]);