|$ curl https://forge-ai.dev/api/markdown?path=docs/js/abort-controller
$cat docs/abortcontroller-&-abortsignal.md
updated Recently·16 min read·published

AbortController & AbortSignal

JavaScriptIntermediate
Introduction

AbortController and AbortSignal provide a standardized way to abort asynchronous operations — fetch requests, streams, event listeners, and custom async tasks. The pattern is built into the Fetch API, ReadableStream, and increasingly adopted by third-party libraries.

Basic Usage

Create an AbortController, pass its signal to fetch, then call abort() to cancel.

abort-fetch.js
JavaScript
1const controller = new AbortController();
2const { signal } = controller;
3
4// Start a fetch that can be aborted
5fetch("/api/data", { signal })
6 .then(res => res.json())
7 .then(data => console.log(data))
8 .catch(err => {
9 if (err.name === "AbortError") {
10 console.log("Request was cancelled");
11 } else {
12 console.error("Other error:", err);
13 }
14 });
15
16// Cancel the request
17controller.abort();
18// Throws DOMException: AbortError
Timeout Pattern

Combine AbortSignal with timeout for race-against-time scenarios.

abort-timeout.js
JavaScript
1function fetchWithTimeout(url, ms = 5000) {
2 const controller = new AbortController();
3 const timeoutId = setTimeout(() => controller.abort(), ms);
4
5 return fetch(url, { signal: controller.signal })
6 .finally(() => clearTimeout(timeoutId));
7}
8
9// Usage
10try {
11 const res = await fetchWithTimeout("/api/data", 3000);
12 const data = await res.json();
13} catch (err) {
14 if (err.name === "AbortError") {
15 console.error("Request timed out");
16 }
17}
18
19// Static timeout helper (Chrome 103+, Node 18+)
20const res = await fetch("/api/data", {
21 signal: AbortSignal.timeout(5000),
22});
Custom Abortable Tasks

Integrate AbortSignal into your own async patterns.

abort-custom.js
JavaScript
1function wait(ms, { signal } = {}) {
2 return new Promise((resolve, reject) => {
3 if (signal?.aborted) {
4 return reject(new DOMException("Aborted", "AbortError"));
5 }
6
7 const timer = setTimeout(resolve, ms);
8
9 signal?.addEventListener("abort", () => {
10 clearTimeout(timer);
11 reject(new DOMException("Aborted", "AbortError"));
12 }, { once: true });
13 });
14}
15
16const controller = new AbortController();
17setTimeout(() => controller.abort(), 500);
18
19try {
20 await wait(2000, { signal: controller.signal });
21} catch {
22 console.log("Wait was aborted");
23}

info

Always check signal.aborted synchronously before starting async work. Listen to the abort event to clean up resources (timers, streams, connections) immediately.