Suggest an editImprove this articleRefine the answer for “What is AbortController?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**AbortController** - a browser API that creates a cancellation signal for fetch requests. ```javascript const controller = new AbortController(); fetch('/api/data', { signal: controller.signal }); controller.abort(); // Cancels the request, throws AbortError ``` **Key point:** always create a new AbortController per request. An aborted signal stays aborted permanently and fails instantly if reused.Shown above the full answer for quick recall.Answer (EN)Image**AbortController** - a browser Web API that creates an AbortSignal to cancel fetch requests before the response arrives. ## Theory ### TL;DR - Think of it like a fire alarm: pull it and the fetch stops before the response reaches your component - Main use: cancel API calls when a React component unmounts, avoiding "setState on unmounted component" warnings - `controller.abort()` dispatches an abort event synchronously, closing the TCP socket - Decision rule: use it when a request takes more than 500ms or the component might unmount first - AbortError is not a network failure. Always check `err.name !== 'AbortError'` before showing errors to users ### Quick example ```javascript const controller = new AbortController(); fetch('/api/user', { signal: controller.signal }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => { if (err.name === 'AbortError') console.log('Request canceled'); else console.error(err); }); controller.abort(); // Output: "Request canceled" ``` Passing `signal` to fetch ties that request to the controller. Call `abort()` and the network layer closes the socket. No response processed, no state updated. ### Key difference Before AbortController, developers used manual timeouts to "cancel" requests. Timeouts guess duration upfront and waste bandwidth on fast responses that were never needed. AbortController cancels at exactly the right moment: when you decide, not when a timer fires. ### When to use - Component unmounts before the API responds: add AbortController to useEffect cleanup - User types a new search term before the old request finishes: cancel the previous one - Race condition between tab views loading stale data: abort the old fetch - Skip it for requests under 100ms or for APIs that don't accept an AbortSignal (like setTimeout) ### How it works internally When you call `new AbortController()`, the browser allocates an AbortSignal with an `aborted` flag set to false. Calling `controller.abort()` flips that flag to true and fires an 'abort' event synchronously. The fetch API listens to that event and tells the C++ network layer to close the TCP socket immediately. Node.js 15+ has the same mechanism via the undici HTTP client. No polyfills needed for modern environments. ### Common mistakes **Forgetting the cleanup return in useEffect** ```javascript // Wrong: no abort on unmount useEffect(() => { const controller = new AbortController(); fetch('/api/data', { signal: controller.signal }).then(setData); }, []); // Missing return means fetch runs after unmount, React prints a warning ``` Fix: return `() => controller.abort()` from the effect. That one line is all the cleanup you need. **Reusing an aborted controller** ```javascript const controller = new AbortController(); controller.abort(); fetch('/api/new', { signal: controller.signal }); // Fails immediately ``` An aborted signal stays aborted. The fetch throws AbortError before any network activity. I've seen this trip up seniors during rushed refactors. Always create `new AbortController()` per request. **Treating AbortError as a real failure** ```javascript // Wrong: shows error toast on intentional cancel fetch('/api').catch(err => showErrorToast(err)); ``` Fix: `if (err.name !== 'AbortError') showErrorToast(err);` **Assuming axios supports signal automatically** Axios v1.6+ accepts `signal` in config. Older versions ignore it with no warning. Check your version, or use native fetch for this pattern. ### Real-world usage - React Query: auto-passes `signal` to your query function, aborts on component unmount - SWR: passes AbortSignal to the fetcher for stale-while-revalidate cancellations - RTK Query: `createApi` aborts in-flight queries when the component disposes - Express (Node.js): `res.setTimeout(5000, () => controller.abort())` for hung connections - `AbortSignal.timeout(5000)`: static shorthand that auto-aborts after a set time, no manual `abort()` call needed ### Follow-up questions **Q:** What happens if you call `abort()` after the response already arrived? **A:** Nothing. AbortController only closes the socket before the response is buffered. Once fetch has the response, aborting has no effect. **Q:** What is the difference between `AbortSignal.timeout()` and AbortController? **A:** `AbortSignal.timeout(5000)` auto-aborts after 5 seconds with no extra code. AbortController is a manual trigger: you call `abort()` when user action or component lifecycle says to. Use timeout for simple time limits, AbortController for everything else. **Q:** What browser versions support AbortController? **A:** Chrome 66+, Firefox 57+, Safari 12.1+. Node.js 15+ natively. For older Node, the `abort-controller` npm package works. **Q:** How do you cancel multiple parallel requests with one controller? **A:** Pass the same signal to all fetch calls. One `abort()` cancels all of them. But that removes independent control. For separate cancellation, create one controller per request. ## Examples ### Basic: cancel on component unmount ```javascript import { useEffect, useState } from 'react'; function ProductDetails({ productId }) { const [product, setProduct] = useState(null); useEffect(() => { const controller = new AbortController(); fetch(`/api/products/${productId}`, { signal: controller.signal }) .then(res => res.json()) .then(setProduct) .catch(err => { if (err.name !== 'AbortError') console.error(err); }); return () => controller.abort(); // Runs on unmount or when productId changes }, [productId]); return product ? <h1>{product.name}</h1> : <p>Loading...</p>; } ``` When `productId` changes, React runs the cleanup before the next effect fires. That cleanup calls `abort()`, canceling the previous request. Only the latest response updates state. ### Intermediate: live search with automatic cancellation ```javascript import { useEffect, useState } from 'react'; function UserSearch({ query }) { const [users, setUsers] = useState([]); useEffect(() => { if (!query) return; const controller = new AbortController(); fetch(`/api/users?q=${query}`, { signal: controller.signal }) .then(res => res.json()) .then(setUsers) .catch(err => { if (err.name !== 'AbortError') console.error('Search failed:', err); }); return () => controller.abort(); // Cancel on next keystroke }, [query]); return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>; } // No stale results, no "setState on unmounted component" warning ``` Each `query` change triggers cleanup, which cancels the previous fetch. The new effect starts a fresh controller. Users see results for their latest input, not for some earlier keystroke.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.