Today, I came across a code snippet that used Promise.race
which I hadn't seen before:
let response
try {
const maxTime = 5000
const promise = fetch(apiUrl);
const timeout = new Promise((resolve) => {
setTimeout(resolve, maxTime);
});
response = await Promise.race([promise, timeout]);
} catch (e) {
console.error(e);
}
return response
The Promise.race()
method takes an array of promises and returns a new promise. The returned promise settles (resolves or rejects) as soon as one of the input promises settles. The settlement value of the returned promise is the same as the settlement value of the first settled promise.
One clever use case for Promise.race
is implementing timeout functionality. By creating a promise that resolves after a specified delay and racing it against another promise, you can enforce a timeout on the operation.
In the code snippet above:
fetch
).By using Promise.race([promise, timeout])
, the code waits for either the API request to complete or the timeout to occur, whichever happens first.
In a browser, when you're using fetch()
to make requests, the timeout length is dictated by the browser defaults (300 seconds for Chrome, 90 seconds for Firefox). To adjust the default timeout lengths, the fetch()
API doesn't have built-in functionality, so the AbortController interface needs to be used to stop a request after a specified time.
Using AbortController
, the code above can be modified as follows:
let response
let id
try {
const maxTime = 5000
const controller = new AbortController()
id = setTimeout(() => controller.abort(), maxTime)
response = await fetch(apiUrl, { signal: controller.signal })
} catch (e) {
console.error(e)
}
clearTimeout(id)
return response
After Node 17.3 and in modern browsers, you can also use AbortSignal for this usecase.
let response
try {
const maxTime = 5000
response = await fetch(apiUrl, { signal: AbortSignal.timeout(maxTime) });
} catch (e) {
console.error(e);
}
return response