DEV Community

Cover image for AbortController: The Superpower You Didn’t Know You Needed in JavaScript
Ítalo Queiroz
Ítalo Queiroz

Posted on

3 1

AbortController: The Superpower You Didn’t Know You Needed in JavaScript

Have you ever found yourself in a situation where an HTTP request is stuck in limbo, an eventListener refuses to leave, or a timeout decides to wreak havoc on your app? If so, you need to meet AbortController. It’s like that friend who knows exactly when to say, “enough is enough,” and save the day.

Today, we’ll explore how AbortController can be used to cancel fetch requests, clean up eventListeners, and even manage timeouts. All with practical examples in plain JavaScript and React. And of course, with a touch of humor—because dev life is already complicated enough!


What is AbortController?

The AbortController is a native JavaScript interface that allows you to cancel asynchronous operations, such as HTTP requests, before they complete. It works hand-in-hand with AbortSignal, which is used to communicate the cancellation.

How does it work?

  1. You create an AbortController.
  2. Use the signal associated with it to "monitor" the asynchronous operation.
  3. When you want to cancel, call the abort() method.

That’s it! Now, let’s see it in action.


1. Canceling Fetch Requests

Imagine you’re downloading a video, but the user decides to cancel the download. Without AbortController, the request would continue until completion, wasting resources. With it, you can stop the process midway.

let controller;
const url = "video.mp4";

const downloadBtn = document.querySelector(".download");
const abortBtn = document.querySelector(".abort");

downloadBtn.addEventListener("click", fetchVideo);

abortBtn.addEventListener("click", () => {
  if (controller) {
    controller.abort();
    console.log("Download canceled!");
  }
});

async function fetchVideo() {
  controller = new AbortController();
  const signal = controller.signal;

  try {
    const response = await fetch(url, { signal });
    console.log("Download complete:", response);
    // Process the video here
  } catch (err) {
    if (err.name === "AbortError") {
      console.log("Request aborted!");
    } else {
      console.error("Download error:", err);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Here, the "Cancel" button calls the abort() method on the controller, stopping the request. If the fetch has already completed, an AbortError is thrown.


2. Cleaning Up EventListeners

How many times have you forgotten to remove an eventListener, leaving it to consume memory and cause bugs? With AbortController, you can associate a signal with the listener and automatically remove it when needed.

const controller = new AbortController();

function handleClick(event) {
  console.log("Button clicked!", event);
}

// Add the listener with the AbortController's signal
document.querySelector("button").addEventListener("click", handleClick, { signal: controller.signal });
//Or you can pass the AbortController instance
//document.querySelector("button").addEventListener("click", handleClick, controller);

console.log("EventListener added!");

// After 5 seconds, remove the listener
setTimeout(() => {
  controller.abort();
  console.log("EventListener automatically removed!");
}, 5000);
Enter fullscreen mode Exit fullscreen mode

With this, you’ll never have to worry about forgotten eventListeners again. The abort() method takes care of everything for you.


3. Managing Timeouts

And what about when a request takes too long? Instead of waiting forever, you can use AbortController to set a timeout and automatically cancel the operation.

const controller = new AbortController();
const timeoutId = setTimeout(() => {
  controller.abort();
  console.log("Timeout: request canceled!");
}, 3000); // Cancel after 3 seconds

fetch("https://api.example.com/data", { signal: controller.signal })
  .then(response => {
    clearTimeout(timeoutId); // Clear the timeout if the response arrives in time
    return response.json();
  })
  .then(data => console.log("Data received:", data))
  .catch(err => {
    if (err.name === "AbortError") {
      console.log("Request aborted due to timeout!");
    } else {
      console.error("Unexpected error:", err);
    }
  });
Enter fullscreen mode Exit fullscreen mode

This ensures that slow requests don’t interfere with the user experience.


4. Using AbortController in React

In React, AbortController is especially useful for avoiding memory leaks when components unmount before a request is completed.

import React, { useState, useEffect } from "react";

function MyComponent() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    const controller = new AbortController();
    const signal = controller.signal;

    const fetchData = async () => {
      setLoading(true);
      try {
        const response = await fetch("https://api.example.com/data", { signal });
        if (!response.ok) {
          throw new Error(`HTTP error: ${response.status}`);
        }
        const data = await response.json();
        setData(data);
      } catch (err) {
        if (err.name !== "AbortError") {
          setError(err);
        }
      } finally {
        setLoading(false);
      }
    };

    fetchData();

    return () => {
      controller.abort(); // Cancel the request when the component unmounts
    };
  }, []);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;
  if (!data) return <p>No data available.</p>;

  return (
    <div>
      <h3>Data Received:</h3>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

export default MyComponent;
Enter fullscreen mode Exit fullscreen mode

Here, the AbortController ensures that if the component unmounts before the request finishes, it will be canceled, preventing memory leaks.


Conclusion

The AbortController is a powerful and versatile tool that can greatly simplify the management of asynchronous operations in your code. Whether it’s canceling requests, cleaning up eventListeners, or managing timeouts, it helps keep your code cleaner, more efficient, and bug-free.

Retry later

Top comments (0)

Retry later
Retry later