How to set a timeout for fetch
Short answer
fetch() itself waits as long as needed. AbortSignal.timeout() creates a signal that cancels the request after the given number of milliseconds:
const response = await fetch('/api/report', { signal: AbortSignal.timeout(5000) });Recognizing a timeout
On a timeout the error has the name TimeoutError, on a manual cancel it is AbortError:
try {
const response = await fetch('/api/report', { signal: AbortSignal.timeout(5000) });
const report = await response.json();
} catch (error) {
if (error.name === 'TimeoutError') {
showMessage('The server is taking too long. Try again later.');
} else {
throw error;
}
}With AbortController
AbortController gives a signal you can cancel yourself, for example with a button or on a timer:
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch('/api/report', { signal: controller.signal });
console.log(await response.json());
} finally {
clearTimeout(timer);
}How it works
Any promise-based operation that accepts a signal behaves the same way. A small example without the network:
const signal = AbortSignal.timeout(50);
await new Promise((resolve) => setTimeout(resolve, 100));
console.log(signal.aborted, signal.reason.name);Output:
true TimeoutErrorCommon mistake
A timer with setTimeout() alone does not stop the request: it keeps loading in the background. Pass a signal to fetch() so the request is really cancelled.
// the request continues even after the message
setTimeout(() => showMessage('Too slow'), 5000);
const response = await fetch('/api/report');Functions used in this recipe
- fetch — Sends an HTTP request and returns a promise of the response.