Table Of Contents
Quick Fix: Basic Request Cancellation
// Create AbortController
const controller = new AbortController();
// Make request with signal
const fetchPromise = fetch('https://api.example.com/slow-endpoint', {
signal: controller.signal
});
// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);
try {
const response = await fetchPromise;
const data = await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request was cancelled');
}
}
Node.js Built-in Solution: Advanced Abort Patterns
const axios = require('axios');
// Axios with AbortController (v0.22+)
const controller = new AbortController();
axios.get('https://api.example.com/data', {
signal: controller.signal
})
.then(response => console.log(response.data))
.catch(error => {
if (axios.isCancel(error)) {
console.log('Request cancelled:', error.message);
}
});
// Cancel on user action
document.getElementById('cancelBtn').addEventListener('click', () => {
controller.abort('User cancelled operation');
});
// Timeout with AbortController
function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => {
controller.abort('Request timeout');
}, timeout);
return fetch(url, { signal: controller.signal })
.finally(() => clearTimeout(timeoutId));
}
// Race multiple requests, cancel losers
async function fetchFastest(urls) {
const controllers = urls.map(() => new AbortController());
const promises = urls.map((url, index) =>
fetch(url, { signal: controllers[index].signal })
.then(response => ({ response, index }))
);
try {
const { response, index } = await Promise.race(promises);
// Cancel other requests
controllers.forEach((controller, i) => {
if (i !== index) controller.abort();
});
return response;
} catch (error) {
// Cancel all if race fails
controllers.forEach(c => c.abort());
throw error;
}
}
// Cleanup on component unmount (React example)
function useApiCall(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') {
console.error(err);
}
})
.finally(() => setLoading(false));
// Cleanup function
return () => controller.abort();
}, [url]);
return { data, loading };
}
// Abort multiple related operations
class RequestManager {
constructor() {
this.controllers = new Map();
}
async request(id, url, options = {}) {
// Cancel previous request with same ID
this.cancel(id);
const controller = new AbortController();
this.controllers.set(id, controller);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
this.controllers.delete(id);
return response;
} catch (error) {
if (error.name === 'AbortError') {
console.log(`Request ${id} was aborted`);
}
throw error;
}
}
cancel(id) {
const controller = this.controllers.get(id);
if (controller) {
controller.abort();
this.controllers.delete(id);
}
}
cancelAll() {
this.controllers.forEach(controller => controller.abort());
this.controllers.clear();
}
}
// Custom abort with reason
const controller = new AbortController();
controller.signal.addEventListener('abort', () => {
console.log('Aborted with reason:', controller.signal.reason);
});
controller.abort({ code: 'USER_CANCELLED', message: 'User clicked cancel' });
AbortController solves "cancel pending requests", "component cleanup", and "timeout handling" issues. Built into Node.js 15+ and modern browsers. Works with fetch, axios 0.22+, and Node streams. Alternative: axios CancelToken (deprecated), p-cancelable for promises.
Share this article
Add Comment
No comments yet. Be the first to comment!