You can cancel an in-flight fetch request by passing an AbortController signal to fetch and calling abort() when the user leaves a page, times out, or starts a newer request.
What it is
AbortController is a standard web API for cancelling asynchronous operations that support cancellation. It creates a signal object that you pass to APIs such as fetch(). When you call controller.abort(), the signal becomes aborted, and the operation rejects with an AbortError. Related terms include AbortSignal, signal.aborted, and the abort event.
Why it matters
- Prevents stale responses from overwriting newer UI state, such as search results.
- Reduces wasted bandwidth and server work when a user navigates away quickly.
- Provides a clean way to implement request timeouts.
- Helps single-page apps cancel requests during route changes.
- Makes cancellation explicit instead of ignoring late promises.
Syntax or steps
- Create a controller:
const controller = new AbortController(); - Pass its signal to fetch:
fetch(url, { signal: controller.signal }); - Call
controller.abort();when cancellation is needed. - Catch the resulting
AbortErrorand treat it as cancellation, not failure.
Example
const controller = new AbortController();
async function loadUser(id) {
try {
const response = await fetch(`/api/users/${id}`, {
signal: controller.signal
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === "AbortError") {
console.log("Request cancelled");
return null;
}
throw error;
}
}
// Cancel after 2 seconds if still running
setTimeout(() => controller.abort(), 2000);
loadUser(42).then(user => {
if (user) console.log(user);
});
Part-by-part explanation
new AbortController()creates the controller and its associated signal.signal: controller.signaltellsfetch()to watch for cancellation.setTimeout(() => controller.abort(), 2000)aborts the request after two seconds.- The
catchblock checkserror.name === "AbortError"so cancelled requests do not crash the app. - Returning
nulllets the caller decide what to show when no data arrives.
Common mistakes
- Forgetting to catch
AbortError, which can cause an unhandled promise rejection. - Reusing an aborted controller for a new request; create a fresh
AbortControllereach time. - Assuming
abort()stops the server immediately; it cancels the client-side fetch, but server work may continue. - Calling
controller.abort()without passingcontroller.signaltofetch().
When to use it
Use AbortController when you need manual cancellation, such as replacing an old request with a newer one. For simple timeouts, AbortSignal.timeout(ms) can be shorter where supported. Do not use Promise.race() alone if you need to stop the network request; it only ignores the result.
| Need | Use | Why |
|---|---|---|
| User cancels or new request replaces old | AbortController | Gives you explicit control over when to abort. |
| Simple timeout | AbortSignal.timeout(ms) | Creates a signal that aborts automatically after a delay. |
| Cancel custom async work | AbortController plus signal.addEventListener("abort", ...) | The signal can notify your own code to stop. |
| Only ignore late results | Request ID check | Useful when cancellation is not possible or not needed. |
Practice
Guided exercise: write fetchWithTimeout(url, ms) that fetches a URL and cancels if it takes longer than ms. Expected behavior: the returned promise rejects with AbortError after the timeout.
Challenge: build an autocomplete handler that cancels the previous request whenever the user types a new character. Hint: keep the current controller in an outer variable, call oldController.abort() before starting a new request, then create a new controller.
Quick check
Question: What error does fetch() reject with when its signal is aborted?
Answer: An AbortError, usually checked with error.name === "AbortError".
Summary
AbortController gives JavaScript a standard way to cancel asynchronous work that accepts a signal, especially fetch(). Pass the signal, abort when appropriate, and handle AbortError so cancelled requests do not look like failures.