How to Cancel a Fetch Request

By  on  

JavaScript promises have always been a major win for the language -- they've led to a revolution of asynchronous coding that has vastly improved performance on the web. One shortcoming of native promises is that there's no true way to cancel a fetch...until now. A new AbortController has been added to the JavaScript specification that will allow developers to use a signal to abort one or multiple fetch calls.

Here's the flow of how canceling a fetch call works:

  • Create an AbortController instance
  • That instance has a signal property
  • Pass the signal as a fetch option for signal
  • Call the AbortController's abort property to cancel all fetches that use that signal.

Aborting a Fetch

The following is the bare bones of canceling a fetch request:

const controller = new AbortController();
const { signal } = controller;

fetch("http://localhost:8000", { signal }).then(response => {
    console.log(`Request 1 is complete!`);
}).catch(e => {
    console.warn(`Fetch 1 error: ${e.message}`);
});

// Abort request
controller.abort();

An AbortError occurs upon the abort call, so you can listen for aborted fetches in the catch by comparing the error name:

}).catch(e => {
    if(e.name === "AbortError") {
        // We know it's been canceled!
    }
});

Passing the same signal to multiple fetch calls will cancel all requests with that signal:

const controller = new AbortController();
const { signal } = controller;

fetch("http://localhost:8000", { signal }).then(response => {
    console.log(`Request 1 is complete!`);
}).catch(e => {
    console.warn(`Fetch 1 error: ${e.message}`);
});

fetch("http://localhost:8000", { signal }).then(response => {
    console.log(`Request 2 is complete!`);
}).catch(e => {
    console.warn(`Fetch 2 error: ${e.message}`);
});

// Wait 2 seconds to abort both requests
setTimeout(() => controller.abort(), 2000);

In his article Abortable fetch, Jake Archibald details a nice utility for creating abortable fetches without the need for all of the boilerplate:

function abortableFetch(request, opts) {
  const controller = new AbortController();
  const signal = controller.signal;

  return {
    abort: () => controller.abort(),
    ready: fetch(request, { ...opts, signal })
  };
}

If I'm completely honest, I'm not super excited about the method for canceling fetches. In an ideal world, a basic .cancel() on the Promise returned by a fetch would be cool, but there are issues that would come with that too. In any event, I'm jazzed about being able to cancel fetch calls and you should be too!

Recent Features

  • By
    9 Mind-Blowing WebGL Demos

    As much as developers now loathe Flash, we're still playing a bit of catch up to natively duplicate the animation capabilities that Adobe's old technology provided us.  Of course we have canvas, an awesome technology, one which I highlighted 9 mind-blowing demos.  Another technology available...

  • By
    Being a Dev Dad

    I get asked loads of questions every day but I'm always surprised that they're rarely questions about code or even tech -- many of the questions I get are more about non-dev stuff like what my office is like, what software I use, and oftentimes...

Incredible Demos

  • By
    CSS Tooltips

    We all know that you can make shapes with CSS and a single HTML element, as I've covered in my CSS Triangles and CSS Circles posts.  Triangles and circles are fairly simply though, so as CSS advances, we need to stretch the boundaries...

  • By
    Do / Undo Functionality with MooTools

    We all know that do/undo functionality is a God send for word processing apps. I've used those terms so often that I think of JavaScript actions in terms of "do" an "undo." I've put together a proof of concept Do/Undo class with MooTools. The MooTools...

Discussion

  1. Fred

    I would love to know what happens under the hood: is the cancellation handled only locally, does it involve some action toward the server?

    I tried to cancel a request a while ago and decided it was easier to ignore the response when it arrives.

    • skyboyer

      connection is closed and that’s it. Server may handle that case in the middle of processing request or may go till the very end to realize response it’s not needed anymore. It’s up to backend-side implementation.

  2. Pepe Julian Onziema

    So jazzed right now. Thanks David!

  3. Next article: “How to Show Upload Progress with the Fetch API”.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!