Lesson guide

Learning objectives

  • Explain the main purpose of Fetch: Abort in JavaScript.
  • Identify the syntax, APIs, or concepts introduced in this lesson.
  • Use the examples to predict how JavaScript will behave before you run similar code.
  • Connect this topic to nearby lessons in Network requests.

Real-world context

This lesson matters when you need to recognize where Fetch: Abort fits into real JavaScript programs. As we know, returns a promise.

Key ideas

  • Fetch: Abort is part of the Network requests chapter, so it builds on the surrounding concepts rather than standing alone.
  • Read each code example in two passes: first for the result, then for the rule that explains the result.
  • When a section compares similar features, focus on the condition that makes you choose one feature over another.

Key terms

  • Fetch: Abort
  • Fetch
  • Abort
  • Network requests
  • JavaScript

As we know, fetch returns a promise. And JavaScript generally has no concept of “aborting” a promise. So how can we cancel an ongoing fetch? E.g. if the user actions on our site indicate that the fetch isn’t needed any more.

There’s a special built-in object for such purposes: AbortController. It can be used to abort not only fetch, but other asynchronous tasks as well.

The usage is very straightforward:

The AbortController object

Create a controller:

javascript
let controller = new AbortController();

A controller is an extremely simple object.

  • It has a single method abort(),
  • And a single property signal that allows to set event listeners on it.

When abort() is called:

  • controller.signal emits the "abort" event.
  • controller.signal.aborted property becomes true.

Generally, we have two parties in the process:

  1. The one that performs a cancelable operation, it sets a listener on controller.signal.
  2. The one that cancels: it calls controller.abort() when needed.

Here’s the full example (without fetch yet):

javascript
let controller = new AbortController();
let signal = controller.signal;

// gets the "signal" object
// and sets the listener to trigger when controller.abort() is called
signal.addEventListener('abort', () => alert("abort!"));

controller.abort(); // abort!

alert(signal.aborted);

As we can see, AbortController is just a mean to pass abort events when abort() is called on it.

We could implement the same kind of event listening in our code on our own, without the AbortController object.

But what’s valuable is that fetch knows how to work with the AbortController object. It’s integrated in it.

Using with fetch

To be able to cancel fetch, pass the signal property of an AbortController as a fetch option:

javascript
let controller = new AbortController();
fetch(url, {
  signal: controller.signal
});

The fetch method knows how to work with AbortController. It will listen to abort events on signal.

Now, to abort, call controller.abort():

javascript
controller.abort();

We’re done: fetch gets the event from signal and aborts the request.

When a fetch is aborted, its promise rejects with an error AbortError, so we should handle it, e.g. in try..catch.

Here’s the full example with fetch aborted after 1 second:

javascript
// abort in 1 second
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);

try {
  let response = await fetch('/article/fetch-abort/demo/hang', {
    signal: controller.signal
  });
} catch(err) {
  if (err.name == 'AbortError') { // handle abort()
    alert("Aborted!");
  } else {
    throw err;
  }
}

AbortController is scalable

AbortController is scalable. It allows to cancel multiple fetches at once.

Here’s a sketch of code that fetches many urls in parallel, and uses a single controller to abort them all:

javascript
let urls = [...]; // a list of urls to fetch in parallel

let controller = new AbortController();

// an array of fetch promises
let fetchJobs = urls.map(url => fetch(url, {
  signal: controller.signal
}));

let results = await Promise.all(fetchJobs);

// if controller.abort() is called from anywhere,
// it aborts all fetches

If we have our own asynchronous tasks, different from fetch, we can use a single AbortController to stop those, together with fetches.

We just need to listen to its abort event in our tasks:

javascript
let urls = [...];
let controller = new AbortController();

let ourJob = new Promise((resolve, reject) => { // our task
  ...
  controller.signal.addEventListener('abort', reject);
});

let fetchJobs = urls.map(url => fetch(url, { // fetches
  signal: controller.signal
}));

// Wait for fetches and our task in parallel
let results = await Promise.all([...fetchJobs, ourJob]);

// if controller.abort() is called from anywhere,
// it aborts all fetches and ourJob

Common mistakes

  • Skipping the small examples and then missing the exact rule that Fetch: Abort depends on.
  • Copying code without changing one value at a time to see which part controls the result.
  • Treating similar-looking syntax or APIs as interchangeable before checking their edge cases.

Summary

  • AbortController is a simple object that generates an abort event on its signal property when the abort() method is called (and also sets signal.aborted to true).
  • fetch integrates with it: we pass the signal property as the option, and then fetch listens to it, so it’s possible to abort the fetch.
  • We can use AbortController in our code. The “call abort()” → “listen to abort event” interaction is simple and universal. We can use it even without fetch.

Predict

Before running this abort model, predict the eight output lines. It models AbortController.signal, fetch integration, catching AbortError, and using one controller to cancel multiple jobs.

javascript
Reveal explanation

The output is abort event, fetch aborted:/slow, job aborted:cleanup-cache, signal:true, caught:AbortError, fetch aborted:/a, fetch aborted:/b, and fetch aborted:/c. AbortController is a small coordination object: calling abort() flips signal.aborted and emits an abort event. Fetch listens to that signal and rejects with an AbortError, which should be handled separately from real network or parsing failures. The same signal can be shared by multiple fetches and by custom async jobs, so one controller can cancel a whole group of related work.

Try it

Create a separate controller for /c, then predict which fetch is no longer canceled by shared.abort().

Practice

  • Rewrite one example from this lesson without looking at the original, then run it and compare the result.
  • Change one input, operator, method call, or option in a code sample and predict what will happen before running it.
  • Explain Fetch: Abort in your own words as if you were reviewing it with another learner.

Keep learning

Continue with Fetch: Cross-Origin Requests when you are ready for the next lesson.