W3docs

Fetch: abort

Learn how to cancel fetch requests in JavaScript with AbortController and AbortSignal. Covers user-triggered aborts and request timeouts.

Once a fetch() request is in flight, it keeps running until the server responds — even if the user has navigated away, typed a new search term, or the answer is no longer needed. Those wasted requests tie up connections, burn battery and bandwidth, and can deliver stale results that overwrite fresh ones. The AbortController interface gives you a clean, standard way to cancel a request on demand.

This chapter shows how to wire up AbortController, react to user actions, build timeouts, cancel several requests at once, and handle the resulting AbortError properly. To find out more about fetch itself, see the previous page, Fetch API.

How AbortController works

AbortController is a tiny object with one job: it owns an AbortSignal and can flip that signal to the aborted state. The signal is the part you hand to fetch() (and to many other browser APIs, such as addEventListener). When you call controller.abort(), every operation that received that signal is cancelled.

The pattern is always the same three steps:

  1. Create a controller: const controller = new AbortController().
  2. Pass controller.signal to fetch() in the options object.
  3. Call controller.abort() whenever you want to cancel.

When a fetch is aborted, its promise rejects with a DOMException whose name is "AbortError". That is why every example below checks error.name === 'AbortError' — so you can ignore the deliberate cancellation while still surfacing real network failures.

Basic usage of AbortController

Here is the smallest complete example. It aborts immediately so you can see the rejection path:

javascript— editable

We create an AbortController, pass its signal to fetch(), and immediately call controller.abort(). Because the request never completes normally, the .catch() runs and reports the abort.

Inspecting the signal: aborted and the abort event

The signal exposes its state so other code can react to a cancellation. Two members matter most:

  • signal.aborted — a boolean that becomes true once aborted.
  • the "abort" event — fired on the signal the moment abort() is called.
javascript— editable

This is handy when you have non-fetch work (a timer, an animation, a stream reader) that should stop the moment the request is cancelled.

One controller, one use. A controller cannot be reset. Once you call abort(), that signal stays aborted forever, and any new fetch() you start with it rejects instantly. For a fresh request, create a new AbortController.

Practical example: aborting on a user action

The most common reason to abort is a user changing their mind — clicking "Cancel", closing a dialog, or typing a new query before the previous one finished. Here a button cancels an in-progress request:

<body>
  <button id="abortButton">Abort Fetch Request</button>
  <script>
    const controller = new AbortController();
    const signal = controller.signal;
    document.getElementById('abortButton').addEventListener('click', () => {
      controller.abort();
    });
    fetch('https://httpbin.org/delay/5', { signal })
      .then(response => response.json())
      .then(data => alert(
        'Data is successfully fetched! Refresh the page and try aborting.'
      ))
      .catch(error => {
        if (error.name === 'AbortError') {
          alert('Fetch request was aborted by the user');
        } else {
          alert('Fetch error: ' + error.message);
        }
      });
  </script>
</body>

Clicking the button with the ID abortButton cancels the ongoing fetch request. The endpoint https://httpbin.org/delay/5 deliberately takes 5 seconds, so if you click within that window the request rejects with AbortError.

Aborting several requests at once

A single signal can be passed to many requests. One call to controller.abort() then cancels all of them — useful when a page leaves a view that started several parallel loads:

javascript— editable

Because all three requests share one signal, controller.abort() cancels them in a single call and Promise.all rejects with AbortError. To learn more about running requests in parallel, see Promise API.

Aborting after a timeout

A very common use of AbortController is to give a request a deadline: if the server is too slow, cancel and show an error instead of waiting forever.

The manual way with setTimeout

You can pair the controller with a timer and combine it with any other async logic. Here a separate operation triggers the abort after one second, while the endpoint would take five:

javascript— editable

The fetch is aborted by the timer after one second, well before the five-second endpoint can respond. Read more about timers in async/await.

The shortcut: AbortSignal.timeout()

Modern browsers (and Node 17.3+) ship a built-in helper that creates a signal which aborts itself after a given number of milliseconds — no controller or setTimeout needed:

javascript— editable

Note that a timeout abort rejects with a TimeoutError, not an AbortError, so you can tell "took too long" apart from "the user cancelled". If you need both a timeout and a manual cancel button, combine signals with AbortSignal.any([userSignal, AbortSignal.timeout(2000)]).

Handling AbortError correctly

Whenever you abort a fetch, the promise rejects. Forgetting to handle it produces a noisy "uncaught promise rejection" in the console, even though the cancellation was intentional. Two rules keep things clean:

  • Always have a .catch() (or try/catch with await) on an abortable fetch.
  • Inside it, check error.name and treat 'AbortError' / 'TimeoutError' as expected — only log or surface the other errors. See Error handling with promises for the broader pattern.

Conclusion

AbortController is the standard way to cancel fetch() requests in JavaScript. Create a controller, pass its signal to one or more requests, and call abort() whenever the work is no longer needed. You have seen user-triggered cancellation, manual and built-in timeouts, cancelling many requests at once, and how to handle the resulting AbortError. Reaching for these patterns keeps your apps responsive and stops them from wasting time on results nobody is waiting for.

Practice

Practice
What is the purpose of passing the signal property from an AbortController to a fetch request?
What is the purpose of passing the signal property from an AbortController to a fetch request?
Was this page helpful?