, ,

5 Real Examples of Using AbortController to Cancel Fetch Requests

Posted by

Stop unnecessary network calls, prevent race conditions, and make your app snappier with these practical examples.

Stop unnecessary network calls, prevent race conditions, and make your app snappier with these practical examples.

Introduction

Here’s a dirty secret:
 Even experienced developers let old Fetch requests keep running in the background, wasting time, bandwidth, and sometimes even breaking the UI.

That’s why the AbortController API exists to give you full control over in-flight requests.

It’s simple:

  • Create an AbortController
  • Pass its signal to fetch()
  • Call abort() When you want to cancel the request

Let’s see 5 real-world examples where using it makes your app faster, cleaner, and smarter.


Example 1: Canceling a Search While Typing

Every keystroke shouldn’t trigger a new API call that runs to completion.
 You only care about the latest query.

let controller;

async function handleSearch(query) {
// Cancel previous request if still active
if (controller) controller.abort();

controller = new AbortController();

try {
const res = await fetch(`/api/search?q=${query}`, {
signal: controller.signal,
});
const data = await res.json();
console.log("Search results:", data);
} catch (err) {
if (err.name === "AbortError") {
console.log("Old request canceled");
} else {
console.error(err);
}
}
}

// Called on every input change
handleSearch("rea");
handleSearch("react");

✅ Cancels old requests instantly
✅ Prevents race conditions in search suggestions


Example 2: Cleaning Up in React Components

When a component unmounts (like navigating to another page), any ongoing Fetch should be aborted, or you’ll get “state update on unmounted component” warnings.

import { useEffect, useState } from "react";

function UserProfile({ userId }) {
const [user, setUser] = useState(null);

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

fetch(`/api/users/${userId}`, { signal: controller.signal })
.then((res) => res.json())
.then(setUser)
.catch((err) => {
if (err.name !== "AbortError") console.error(err);
});

// Cancel request when unmounting or userId changes
return () => controller.abort();
}, [userId]);

return user ? <p>{user.name}</p> : <p>Loading...</p>;
}

✅ Cancels requests automatically when navigating away
✅ Prevents memory leaks
✅ Keeps your React app clean and stable


Example 3: Timeout for Slow APIs

Some APIs hang forever.
 You can combine AbortController with setTimeout() to cancel after a limit.

async function fetchWithTimeout(url, ms = 5000) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), ms);

try {
const res = await fetch(url, { signal: controller.signal });
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (err) {
if (err.name === "AbortError") {
console.error("Request timed out!");
} else {
console.error("Fetch failed:", err);
}
} finally {
clearTimeout(timeout);
}
}

fetchWithTimeout("/api/data", 3000);

✅ Avoids “infinite loading”
✅ Gives users faster feedback
✅ Useful for flaky or slow backends


Example 4: Canceling Multiple Requests Together

Sometimes you want to cancel a group of requests, for example, when a dashboard page changes or a tab closes.

const controller = new AbortController();

async function loadDashboard() {
try {
const [posts, comments, users] = await Promise.all([
fetch("/api/posts", { signal: controller.signal }),
fetch("/api/comments", { signal: controller.signal }),
fetch("/api/users", { signal: controller.signal }),
]);

console.log("All loaded!");
} catch (err) {
if (err.name === "AbortError") console.log("All requests canceled");
else console.error(err);
}
}

// Cancel them all at once
controller.abort();

✅ Cancels all pending fetches instantly
✅ Saves bandwidth and prevents partial data states


Example 5: Canceling Background Sync or Polling

If your app polls for updates (e.g., notifications), you should stop polling when the user leaves or the tab loses focus.

let controller;

function startPolling() {
controller = new AbortController();

const poll = async () => {
try {
const res = await fetch("/api/notifications", {
signal: controller.signal,
});
const data = await res.json();
console.log("Notifications:", data);

// Repeat every 5s
setTimeout(poll, 5000);
} catch (err) {
if (err.name === "AbortError") {
console.log("Polling stopped");
} else {
console.error(err);
}
}
};

poll();
}

function stopPolling() {
if (controller) controller.abort();
}

startPolling();

// Later...
stopPolling();

✅ Stops background polling immediately
✅ Prevents wasteful network requests when not needed


Common Gotchas

⚠️ Don’t reuse a controller once aborted; it’s permanently “done.”
⚠️ Always check err.name === "AbortError" to handle cancellations cleanly.
⚠️ Pass signal to fetch() abort won’t work otherwise.


Why It Matters

Modern apps are dynamic; users navigate fast, type often, and expect instant updates.
If you’re not canceling redundant requests, your app is:

  • Slower
  • More resource-hungry
  • Prone to data flickering

AbortController is the difference between a reactive UI and a responsible one.

✅ Saves bandwidth
✅ Prevents race conditions
✅ Cleans up async tasks
✅ Improves overall UX


Conclusion

The AbortController API is small but mighty.
It’s the easiest way to control async operations like a pro.

Quick recap:

  1. Cancel old search requests instantly
  2. Clean up Fetch in React
  3. Add custom timeouts
  4. Cancel multiple requests at once
  5. Stop background polling gracefully

Don’t just send requests manage them intelligently.

Once you start canceling unnecessary Fetch calls, you’ll never go back.


Call to Action

Have you ever used AbortController In your apps?
Share your favorite use case (or a bug it helped you fix) in the comments 👇

And if your teammate’s app still makes 10 requests per second for no reason…
Send them this post before their browser melts.

Leave a Reply

Your email address will not be published. Required fields are marked *