ReviseAlgo Logo

Asynchronous JavaScript

Abort Controller & Cancelling Async Operations

Master cancelling asynchronous operations in JavaScript. Learn how to abort fetch requests, remove event listeners dynamically, and build cancellable promises.

Last Updated: July 15, 2026 10 min read

1. Introduction

Historically, once a Promise or fetch request was initiated, it was impossible to cancel it. ES6 introduced the AbortController class as a standard API to cancel asynchronous operations dynamically.

2. Why It Matters

In single-page applications, users often navigate away from pages before search requests or image downloads complete. Cancelling these pending requests saves server resources and bandwidth, preventing slow network performance.

3. Real-World Analogy

Think of a Food Delivery Order Cancel Button:

  • Uncancellable Promise: You place an order. Halfway through, you realize you ordered from the wrong restaurant. There is no cancellation button. The kitchen prepares the food, the driver drives to your house, and you are charged, even if you throw the food away.
  • AbortController (Cancel Request): You click "Cancel Order" on the app. The app sends a signal (Abort Signal) to the restaurant. The kitchen stops cooking immediately, the driver is redirected, and the transaction cancels, saving resources.

4. How It Works

The cancellation mechanism consists of two parts:
1. AbortController: The controller object that manages the operation. It exposes an abort() method to trigger the cancellation.
2. AbortSignal: The read-only signal property passed to asynchronous functions (like the fetch API). It allows them to monitor the abort status.

5. Architectural Uses of AbortController

AbortController is not limited to fetch requests:
Event Listener Removal: You can pass an abort signal to addEventListener option parameter, allowing you to remove a group of listeners at once by calling abort().
Cancellable Promises: You can check the signal.aborted property inside custom Promises to reject them early if aborted.

6. Practical Example

This script demonstrates implementing a request timeout wrapper using AbortController:

7. Common Mistakes

  • Not checking for AbortError in catch blocks: Treat aborted requests differently than real failures (like network or parsing errors) to prevent showing false error alerts to users.
  • Reusing the same controller: Once abort() is called, the signal state remains aborted. Create a new controller instance for subsequent requests.

8. Quick Quiz

Q1: What error name is thrown when a fetch request is aborted?

A) CancelError

B) AbortError

Answer: B — Aborting a fetch request causes it to reject with a DOMException named "AbortError".

9. Scenario-Based Challenge

The Search Auto-Suggest Cancellation:

As a user types in a search box, requests are sent to the server. If a new request is sent before the previous one completes, cancel the old request to prevent out-of-order responses. Write a wrapper using AbortController to implement this cancellation logic.

10. Debugging Exercise

Identify why this component class fails on its second fetch run:

class DataFetcher {
  controller = new AbortController();

async load(url) { // Bug: Reusing the same controller without resetting it! return fetch(url, { signal: this.controller.signal }).then(r => r.json()); }

cancel() { this.controller.abort(); } } const api = new DataFetcher(); api.load('/data'); api.cancel(); // Cancel first load api.load('/data'); // rejects immediately with AbortError! Why?

View Solution

Diagnosis: Calling abort() marks the controller's signal as aborted permanently. Reusing the same controller instance for a new request causes the new request to reject with an AbortError immediately.

Fix: Create a new AbortController instance for every load request:

class DataFetcher {
  controller = null;

async load(url) { if (this.controller) this.controller.abort(); // Cancel previous load if still running this.controller = new AbortController(); return fetch(url, { signal: this.controller.signal }).then(r => r.json()); } }

11. Interview Questions

🟢 Q1: Explain how AbortController is used to cancel fetch requests, event listeners, and custom Promises.

Answer:
Fetch Requests: Pass the controller.signal as an option to the fetch() call. Calling controller.abort() cancels the network request, causing the fetch Promise to reject with an AbortError.
Event Listeners: Pass the signal inside the options object when calling addEventListener. Calling abort() automatically removes the event listener.
Custom Promises: Inside the Promise executor, register an event listener on the signal: signal.addEventListener('abort', () => reject(new AbortError())). If aborted, reject the promise explicitly and clean up any active timers or connections.

12. Production Considerations

  • Resource Cleanup: In React applications, use AbortController inside useEffect hooks to cancel pending network requests if the component unmounts before the request completes, preventing memory leaks and state updates on unmounted components.