AbortController

AbortController is a built-in object that produces a reusable signal you hand to async work, so calling its abort() method can cancel a fetch, timer, or any operation listening to that signal.

Learn AbortController in our free JavaScript course — an interactive lesson with runnable examples, a practice exercise and a quick reference.

Part of the free JavaScript course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

It is how you stop work you no longer need: cancelling a stale search request, tearing down a fetch when a component unmounts, or enforcing a hard timeout.

📚 Prerequisites: You should know promises and async/await with try/catch, since aborting surfaces as a rejected promise.

🔔 Real-World Analogy: An AbortController is a fire alarm . The controller is the pull handle; the signal is the wiring that runs to every room. You give the signal to each async task ("listen for the alarm"). Pulling the handle ( abort() ) rings everywhere at once and every task that was listening stops what it is doing.

Create a controller with new AbortController() . It exposes a read-only signal that you pass to the operation you want to be able to cancel, and an abort() method that flips that signal to the aborted state. The signal has an aborted boolean and fires an "abort" event when triggered.

Pass signal to fetch and call abort() to cancel the request. The fetch promise rejects with an AbortError , which you catch and distinguish from a real network failure by checking err.name . This is the classic "cancel the previous search as the user types" pattern:

⚠️ Always check err.name : Treating an AbortError as a real error shows users scary "request failed" messages for something they (or your code) caused on purpose.

The runnable demo below uses a cancellable delay that listens to the signal — exactly the shape fetch follows — so you can watch an abort reject with an AbortError in Node:

Replace the blank with the method that cancels the controller so the event fires.

When you only need a deadline, skip the controller entirely. AbortSignal.timeout(ms) returns a signal that auto-aborts after ms milliseconds. There is also AbortSignal.any([...]) to abort as soon as any of several signals fires — handy for "cancel on either a timeout or the user clicking stop".

Replace the blank so the code checks for a deliberate abort instead of treating it as a real error.

Predict the output before revealing the answer.

true — abort() permanently flips the signal's aborted flag.

No — the signal stays aborted. Create a fresh new AbortController() for each new operation.

Start two waits. When the fast one finishes, abort the slow one so its cleanup runs. This mirrors cancelling a stale request once fresher data arrives.

Up next: Web Workers — run heavy work off the main thread. 🧵

Practice quiz

What two things does a new AbortController() give you?

  • A signal and an abort() method
  • A promise and a resolve() method
  • Two separate signals
  • A signal and a timeout

Answer: A signal and an abort() method. A controller exposes a read-only signal you hand to async work, plus an abort() method that trips that signal.

After controller.abort(), what is controller.signal.aborted?

  • false
  • true
  • undefined
  • It throws

Answer: true. abort() permanently flips the signal's aborted flag to true.

When you abort a fetch, the fetch promise rejects with what?

  • A plain Error
  • A DOMException whose name is 'AbortError'
  • null
  • A TypeError

Answer: A DOMException whose name is 'AbortError'. An aborted fetch rejects with a DOMException whose name is 'AbortError'.

How do you tell a deliberate cancellation apart from a real network failure?

  • Check err.message
  • Check err.code
  • Check err.name === 'AbortError'
  • You cannot tell them apart

Answer: Check err.name === 'AbortError'. Checking err.name === 'AbortError' distinguishes an intentional abort from a genuine error.

Can you reuse an AbortController after calling abort()?

  • Yes, it resets automatically
  • No — the signal stays aborted forever
  • Only if you call reset()
  • Only for fetch, not timers

Answer: No — the signal stays aborted forever. A signal is one-shot; once aborted it stays aborted, so you create a fresh controller per operation.

What does AbortSignal.timeout(ms) return?

  • A controller
  • A promise
  • A signal that auto-aborts after ms milliseconds
  • A number

Answer: A signal that auto-aborts after ms milliseconds. AbortSignal.timeout(ms) returns a signal that aborts itself after the given delay, with no controller needed.

Which value do you pass to fetch's options?

  • signal: controller
  • signal: controller.signal
  • controller: signal
  • abort: controller

Answer: signal: controller.signal. You pass the signal, not the controller: fetch(url, { signal: controller.signal }).

When a signal created by AbortSignal.timeout fires, signal.reason is a DOMException named what?

  • AbortError
  • TimeoutError
  • RangeError
  • DeadlineError

Answer: TimeoutError. A timeout signal aborts with a DOMException whose name is 'TimeoutError'.

What event does a signal fire when it is aborted?

  • 'cancel'
  • 'stop'
  • 'abort'
  • 'error'

Answer: 'abort'. The signal fires an 'abort' event, which any listener attached to that signal reacts to.

What combines several signals so an operation aborts when ANY of them fires?

AbortSignal.any([...]) aborts as soon as any of the supplied signals fires.