Ever clicked a button twice and accidentally fired off two API calls? Or maybe you started fetching some big data, only to realise you didn’t actually need it anymore. In real life, you’d just hit a Cancel button, right?
Well, JavaScript has a built-in way to do exactly that: AbortController. Think of it like pulling the plug on a task before it finishes.
Example:
Cancelling a fetch request after 2 seconds
const controller = new AbortController();
const signal = controller.signal;
fetch("https://jsonplaceholder.typicode.com/todos/1", { signal })
.then(res => res.json())
.then(data => console.log("Data:", data))
.catch(err => {
if (err.name === "AbortError") {
console.log("❌ Fetch was aborted");
} else {
console.error("Something went wrong:", err);
}
});
// Cancel the request after 2 seconds
setTimeout(() => {
controller.abort();
}, 2000);
Run this, and you’ll see the fetch get cut short. Instead of data, you’ll get an AbortError.
⚙️ How Does It Work?
Think of it like this:
- Controller → The remote control.
- Signal → The wire that connects the remote to the task.
- Task (like fetch) → The TV.
When you call abort(), the signal instantly tells the task: “Stop what you’re doing.”
This really comes in handy when you have multiple filters where each click fires a API call with the latest set of filters. But if user selects multiple filters with some delay, only the new API call with latest filter/s should be alive and the old call are no longer required, in this case we can use abortController to cancel out the previous calls. Another common usecase for this would be when dealing with Forms.
And the most important point of this post is AbortController ≠ Server-Side Cancellation
A common misconception: Aborting the API call will cancel the request.
-> Yes, That's correct (partially), because what you are doing is just aborting the request from client side meaning freeing up the resources that is doing the API handling work on client side by closing the HTTP request. But this doesn't free up the resources on the backend if it was not handled the server still processes the request.. So, calling controller.abort() only stops the client from waiting for a response.
const controller = new AbortController();
fetch('/heavy-operation', { signal: controller.signal })
.catch(err => err.name === 'AbortError' && console.log('Fetch aborted'));
// Later...
controller.abort();
Making Backend Aware: We can achieve this by two approaches
- Passive Approach
- Active Approach
Passive Approach: To truly cancel the operation on the server, detect when the client disconnects
Node.js Example:
// Node.js / Express example
app.get('/heavy-operation', (req, res) => {
req.on('close', () => {
console.log('Client disconnected, aborting server task');
// Stop any ongoing processing here
});
longRunningTask().then(result => res.send(result));
});
Active Approach: Send an explicit cancellation signal
const controller = new AbortController();
const requestId = "12345";
fetch(`/heavy-operation?reqId=${requestId}`, { signal: controller.signal });
// Later, if aborted
controller.abort();
fetch(`/cancel-operation?reqId=${requestId}`); // Tell backend to stop
Server keeps track of requestId tasks and stops processing when /cancel-operation is called.
-> ✅ Stops the browser from receiving the response
-> ❌ Does not stop the server from working
Takeaway:
AbortController makes your UI more responsive by stopping unnecessary client-side waiting, but for truly efficient applications, pair it with server-side cancellation so both frontend and backend resources are freed when a request is no longer needed.
✍️ Co-authored with: @hrithik_pasumarthi
Top comments (0)