AbortController is the standard mechanism for actually cancelling in-progress asynchronous work in JavaScript — fetch requests, event listeners, and any custom async operation that opts in to listening for its signal.
1AbortController | JavaScript Tutorial - In-Depth Guide Part 1
An AbortController creates a 'signal' object that other APIs can listen to, and a 'abort()' method that fires that signal to request cancellation.
const controller = new AbortController();
const signal = controller.signal;
// later, to cancel:
controller.abort();Controller + Signal
2AbortController | JavaScript Tutorial - In-Depth Guide Part 2
fetch() natively supports AbortController via its 'signal' option — aborting the controller rejects the fetch promise with an AbortError.
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.catch((err) => {
if (err.name === 'AbortError') console.log('Request was cancelled');
});
controller.abort();Built Into fetch()
3AbortController | JavaScript Tutorial - In-Depth Guide Part 3
You can also listen for the abort event directly on a signal to add cancellation support to your own custom async functions.
function cancellableDelay(ms, signal) {
return new Promise((resolve, reject) => {
const id = setTimeout(resolve, ms);
signal.addEventListener('abort', () => {
clearTimeout(id);
reject(new DOMException('Aborted', 'AbortError'));
});
});
}Custom Cancellable Functions
4AbortController | JavaScript Tutorial - In-Depth Guide Part 4
AbortSignal.timeout(ms) creates a signal that automatically aborts after a delay — a built-in shortcut that replaces the manual Promise.race()-based timeout pattern.
fetch('/api/slow', { signal: AbortSignal.timeout(5000) });
// automatically aborts after 5 secondsAbortSignal.timeout()
5AbortController | JavaScript Tutorial - In-Depth Guide Part 5
AbortSignal.any([...]) combines multiple signals into one that aborts as soon as any of its sources does — useful for combining a manual cancel button with an automatic timeout.
const userCancel = new AbortController();
const combined = AbortSignal.any([userCancel.signal, AbortSignal.timeout(10000)]);
fetch('/api/data', { signal: combined });Combining Multiple Signals
6Step-by-Step Breakdown
An AbortController creates a 'signal' object that other APIs can listen to, and a 'abort()' method that fires that signal to request cancellation.
fetch() natively supports AbortController via its 'signal' option — aborting the controller rejects the fetch promise with an AbortError.
Checkpoint: When an AbortController tied to a fetch() call is aborted, what happens to the fetch promise?
- →It rejects with an AbortError
- →It resolves with an empty response
You can also listen for the abort event directly on a signal to add cancellation support to your own custom async functions.
AbortSignal.timeout(ms) creates a signal that automatically aborts after a delay — a built-in shortcut that replaces the manual Promise.race()-based timeout pattern.
Checkpoint: Does AbortSignal.timeout(ms) require you to manually write your own setTimeout logic?
- →Yes, it just wraps your own setTimeout call
- →No, it directly produces a signal that auto-aborts after the delay
AbortSignal.any([...]) combines multiple signals into one that aborts as soon as any of its sources does — useful for combining a manual cancel button with an automatic timeout.
Next, we'll explore 'Fetch Cancellation Patterns'.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Cancel Stale Requests Before Updating Live Regions
In a live-search feature, cancelling outdated requests with AbortController prevents an old, superseded response from triggering a confusing or contradictory announcement in an ARIA live region after the user has already moved on to a different query.
SEO Implications
- 1
No Direct SEO Effect
AbortController is a client-side resource-management tool; SEO relevance is limited to overall client-side performance and network efficiency.
Best Practices
Always Pass a signal into fetch() for Requests That Might Need Cancelling
Search-as-you-type, route navigation, and component unmounting are all cases where a previous request becoming irrelevant should be actively cancelled, not just ignored.
Handle AbortError Explicitly and Silently
A cancelled request isn't really a failure from the user's perspective — catch AbortError specifically and skip showing an error message for it, while still surfacing other genuine failures normally.
Frequent Bugs
Treating a cancelled request's AbortError the same as any other fetch failure, showing a confusing "Something went wrong" message to the user for an action they intentionally triggered (like navigating away).
Check `err.name === 'AbortError'` and handle it as an expected, silent case rather than a genuine error.
Creating a new AbortController for every request in a loop but never calling abort() on the previous one, so old requests are never actually cancelled when a newer one supersedes them.
Keep a reference to the current controller, call `.abort()` on it before creating a new one for the next request.
Real-World Examples
Cancelling a Stale Search-as-You-Type Request
A search input fired a new API request on every keystroke, and needed to cancel any previous, now-outdated request before starting a new one.
let controller;
input.addEventListener('input', async (e) => {
controller?.abort();
controller = new AbortController();
try {
const res = await fetch(`/search?q=${e.target.value}`, { signal: controller.signal });
renderResults(await res.json());
} catch (err) {
if (err.name !== 'AbortError') throw err;
}
});