How to cancel Javascript Fetch Request?

When you are working with network requests in your JavaScript app, you might encounter scenarios where you need to handle cancelling network requests.

Last week, I was playing around with a small side project to generate titles using GPT called Title Crafters. In that project, I needed to add a cancel request to the OpenAI API. So, if you are working on a similar app, you might find this useful trick for canceling a fetch request. So let's get started.

Abort Controller

Luckily current modern javascript runtime have builtin support for canceling network request using AbortController.

Today, we will see how to use the AbortController class in our JavaScript application. Here's an example of how it works: you can try clicking this button below.

In short, you just need to add a signal controller to your fetch request.

const controller = new AbortController();
const response = await fetch(url, { signal: controller.signal}).then(...);

// to cancel fetch request use this
controller.abort()

Here's example fetch request that implement cancel signal.

So let's code the fetch request. here's how we would fetch the api using standard request.

const randomPersonBtn = document.getElementById("randomPersonBtn");
async function fetchRandomPerson() {
  const response = await fetch("https://randomuser.me/api/").then((res) =>
    res.json()
  );
  const { name } = response.results[0];
  randomPersonBtn.innerText = `Random person: ${name.first} ${name.last}`;
}
randomPersonBtn.addEventListener("click", fetchRandomPerson);

And if we need to implement a cancel request, we can just attach an abort controller. Now, let's add the abort controller to our fetch request.

The logic is very simple:

  • On button click listener, we attach a network request.
  • We will use the controller and button text as state to check the next incoming click event.
  • When the next incoming click event happens and there are still ongoing network requests, we trigger an abort signal.
  • If the abort signal is performed, then reset the state stop the event.
const randomPersonBtn = document.getElementById("randomPersonBtn");
+let controller = new AbortController();
async function fetchRandomPerson() {
+  if (randomPersonBtn.innerText === "Stop...") {
+    controller.abort();
+    controller = null;
+    controller = new AbortController();
+    randomPersonBtn.innerText = "Random person";
+    return;
+  }
+  randomPersonBtn.innerText = "Stop..."
-  const response = await fetch("https://randomuser.me/api/").then((res) =>
-    res.json()
-  );
+  const wait = (time) =>
+          new Promise((resolve, reject) => setTimeout(resolve, time));
+  const response = await fetch("https://randomuser.me/api/",
+    {signal: controller.signal}).then(async (res) => {
+    await wait(1000*5);
+    return res.json();
+  });
  const { name } = response.results[0];
  randomPersonBtn.innerText = `Random person: ${name.first} ${name.last}`;
}
randomPersonBtn.addEventListener("click", fetchRandomPerson);

Example in React

You can use this on any JavaScript FrontEnd framework like react, vue or svelte etc, here's an example in react.

The logic is still the same as the vanillajs version. We just need a state to store abort controller instance.

import "./styles.css";
import { useState } from "react";

export default function App() {
  const [result, setResult] = useState("");
  const [controller, setController] = useState(null);

  const handleSubmitFetchRandom = async () => {
    const abortController = controller ? controller : new AbortController();
    if (controller === null) {
      setController(abortController);
    } else {
      abortController.abort();
      setController(null);
      return;
    }

    setResult("");
    const response = await fetch("https://randomuser.me/api/", {
      signal: abortController.signal,
    }).then((res) => res.json());
    const { name } = response.results[0];
    setResult(JSON.stringify(name));
    setController(null);
  };

  return (
    <div className="App">
      <h1>AbortController</h1>
      <button onClick={handleSubmitFetchRandom}>
        {controller ? "Stop" : "Random user"}
      </button>
      <pre>{result}</pre>
    </div>
  );
}

Conclusion

There are a lot of npm packages that will help you to work with cancelling network requests. But sometimes you just want to do a simple thing, and AbortController is what you need to work on this kind of scenario.

Hopefully, this is helpful for you. Go try it yourself and let me know if you have any issues with it.