Type fast — watch stale requests cancel
Each keystroke fires a request with random latency. The previous request is aborted the moment you type again — only the final query renders.
Result + Comparison
Start typing to see results
0
Fired
0
Aborted
Without AbortController: stale requests resolve out of order and overwrite fresh data — the user sees results for "r" when they typed "react".
let current = null; async function search(query) { current?.abort(); // cancel previous current = new AbortController(); try { const res = await fetch(url, { signal: current.signal, }); render(await res.json()); } catch (err) { if (err.name !== 'AbortError') showError(err); // ignore aborts } }
One Controller → Many Requests
All 5 requests share one signal. Calling abort() once cancels every pending request simultaneously.
How It Works
0
Completed
0
Aborted
// ONE controller for a group of requests const controller = new AbortController(); const signal = controller.signal; // All share the same signal const requests = urls.map(url => fetch(url, { signal }) ); // Cancel ALL of them at once controller.abort(); // every pending fetch rejects together
Use case: A dashboard loading 5 widgets. If the user navigates away mid-load, one abort() cancels all 5 in-flight requests, freeing bandwidth and connections instantly.
AbortSignal.timeout() — Race the Clock
Set a request latency and a timeout. Whichever finishes first wins — the request completes, or the timeout aborts it with a TimeoutError.
Request takes 2500ms
Timeout at 2000ms
Request
Timeout
Result + Modern Pattern
Set the sliders and run the race
// One line — auto-aborts after 2s const res = await fetch(url, { signal: AbortSignal.timeout(2000), }); // Distinguish WHY it aborted: catch (err) { if (err.name === 'TimeoutError') retry(); // timed out if (err.name === 'AbortError') stayQuiet(); // user cancelled }
Compose signals: AbortSignal.any([userSignal, AbortSignal.timeout(5000)]) aborts on user action OR timeout — whichever happens first.
Read the tutorial