AbortController
new AbortController() Returns:
AbortController · Added in vDOM Living Standard · Updated March 13, 2026 · Built-in Objects async fetch abort controller
The AbortController interface represents a controller object that allows you to abort one or more DOM requests as and when required. You can signal and abort asynchronous operations like fetch requests, enabling you to implement cancellation functionality for network requests, timeouts, and other asynchronous tasks. When abort() is called on an AbortController, it triggers the abort event on the associated AbortSignal, which causes any DOM operation using that signal to throw an AbortError. This API is essential for building responsive applications where users need the ability to cancel pending operations—preventing wasted bandwidth, reducing server load, and improving user experience by eliminating zombie requests that no longer matter.
Syntax
new AbortController()
// TypeScript
const controller: AbortController = new AbortController();
const signal: AbortSignal = controller.signal;
Properties
| Property | Type | Description |
|---|---|---|
signal | AbortSignal | Returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation. |
Methods
| Method | Parameters | Description |
|---|---|---|
abort() | reason?: any | Invokes the abort process, triggering the abort event on the associated AbortSignal. Optional reason parameter available in modern browsers. |
Examples
Basic Fetch with Abort
const controller = new AbortController();
const signal = controller.signal;
fetch('https://jsonplaceholder.typicode.com/posts/1', { signal })
.then(response => response.json())
.then(data => console.log('Data received:', data))
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch aborted');
} else {
console.error('Fetch error:', error);
}
});
// Abort the request after 1 second
setTimeout(() => controller.abort(), 1000);
// Output (after 1 second):
// Fetch aborted
Implementing Request Timeout
function fetchWithTimeout(url, timeout = 3000) {
const controller = new AbortController();
const id = setTimeout(() => controller.abort(), timeout);
return fetch(url, { signal: controller.signal })
.then(response => {
clearTimeout(id);
return response;
})
.catch(error => {
clearTimeout(id);
if (error.name === 'AbortError') {
throw new Error(`Request timed out after ${timeout}ms`);
}
throw error;
});
}
fetchWithTimeout('https://jsonplaceholder.typicode.com/users/1', 2000)
.then(r => r.json())
.then(console.log)
.catch(err => console.error(err.message));
// Output (if request takes > 2 seconds):
// Request timed out after 2000ms
Using AbortController with async/await
async function fetchUserData(userId, signal) {
const response = await fetch(
`https://jsonplaceholder.typicode.com/users/${userId}`,
{ signal }
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
async function loadUserWithCancel() {
const controller = new AbortController();
const loadPromise = fetchUserData(1, controller.signal);
// Cancel after 500ms
setTimeout(() => controller.abort(), 500);
try {
const user = await loadPromise;
console.log('User loaded:', user.name);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Operation cancelled by user');
} else {
console.error('Error:', error.message);
}
}
}
loadUserWithCancel();
// Output:
// Operation cancelled by user
Aborting Multiple Concurrent Requests
async function fetchMultipleUrls(urls) {
const controller = new AbortController();
const fetchPromises = urls.map(url =>
fetch(url, { signal: controller.signal })
.then(r => r.json())
);
// Abort all if any request takes too long
const timeoutId = setTimeout(() => {
console.log('Request timed out, aborting all...');
controller.abort();
}, 3000);
try {
const results = await Promise.allSettled(fetchPromises);
clearTimeout(timeoutId);
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`URL ${urls[index]} succeeded:`, result.value);
} else {
console.log(`URL ${urls[index]} failed:`, result.reason.name);
}
});
} catch (error) {
console.error('All requests aborted');
}
}
fetchMultipleUrls([
'https://jsonplaceholder.typicode.com/users/1',
'https://jsonplaceholder.typicode.com/users/2'
]);
// Output:
// URL https://jsonplaceholder.typicode.com/users/1 succeeded: { id: 1, name: 'Leanne Graham', ... }
// URL https://jsonplaceholder.typicode.com/users/2 succeeded: { id: 2, name: 'Ervin Howell', ... }
Listening to Abort Events
const controller = new AbortController();
const { signal } = controller;
signal.addEventListener('abort', () => {
console.log('Operation has been aborted');
});
signal.addEventListener('abort', () => {
console.log('Cleanup completed');
});
// Trigger abort
controller.abort();
// Output:
// Operation has been aborted
// Cleanup completed
Common Patterns
Cancellation Token Pattern
function createCancellableOperation() {
const controller = new AbortController();
const operation = async () => {
const response = await fetch('/api/data', { signal: controller.signal });
return response.json();
};
return {
execute: operation,
cancel: () => controller.abort(),
signal: controller.signal
};
}
const { execute, cancel, signal } = createCancellableOperation();
// Later: cancel();
Debounced Search with Abort
async function search(query, signal) {
const response = await fetch(`/api/search?q=${query}`, { signal });
return response.json();
}
function debouncedSearch(query, delay = 300) {
let controller;
let timeoutId;
return new Promise((resolve, reject) => {
// Cancel previous request
if (controller) controller.abort();
controller = new AbortController();
clearTimeout(timeoutId);
timeoutId = setTimeout(async () => {
try {
const results = await search(query, controller.signal);
resolve(results);
} catch (error) {
if (error.name !== 'AbortError') reject(error);
}
}, delay);
});
}
Abort Reason (Modern Browsers)
const controller = new AbortController();
fetch('/api/data', { signal: controller.signal })
.catch(error => {
console.log('Abort reason:', error.reason); // "User clicked cancel"
console.log('Error name:', error.name); // "AbortError"
});
controller.abort('User clicked cancel');
See Also
- Fetch:: — HTTP requests with abort signal support
- AbortSignal — The signal object for abort communication
- promise:: — Underlying promise handling for async operations
- Fetch:: — Request object that accepts abort signals