Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
AbortController lets you cancel ongoing operations like fetch requests, file uploads, or any async task. Perfect for when users navigate away, cancel searches, or when requests timeout!
Cancel fetch before completion
Abort slow operations
Cancel old autocomplete queries
See AbortController in action - cancel a slow API call
<div style="max-width: 700px; margin: 0 auto; font-family: 'Segoe UI', sans-serif;">
<div style="background: linear-gradient(135deg, #ef4444 0%, #f43f5e 50%, #ec4899 100%); padding: 40px; border-radius: 16px; text-align: center; box-shadow: 0 10px 30px rgba(239, 68, 68, 0.3);">
<h2 style="color: white; margin: 0 0 12px 0; font-size: 28px; font-weight: 700;">🛑 AbortController Demo</h2>
<p style="color: rgba(255, 255, 255, 0.9); margin: 0 0 30px 0; font-size: 15px;">Start a slow request and cancel it anytime</p>
<div style="display: flex; gap: 12px; justify-content: center; margin-bottom: 30px;">
<button id="startBtn" style="padding: 16px 32px; background: white; color: #ef4444; border: none; border-radius: 12px; cursor: pointer; font-weight: 700; font-size: 16px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); transition: all 0.3s;">
▶️ Start Request
</button>
<button id="cancelBtn" disabled style="padding: 16px 32px; background: #7f1d1d; color: white; border: none; border-radius: 12px; cursor: pointer; font-weight: 700; font-size: 16px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); transition: all 0.3s; opacity: 0.5;">
🛑 Cancel Request
</button>
</div>
<div id="output" style="padding: 24px; background: rgba(255, 255, 255, 0.95); border-radius: 12px; min-height: 120px; backdrop-filter: blur(10px); text-align: left;"></div>
</div>
</div>Loading preview...
Create an AbortController instance
const controller = new AbortController();Pass controller.signal to the async operation
fetch(url, { signal: controller.signal })When you want to cancel, call controller.abort()
controller.abort(); // Cancels the operation!// Create abort controller
const controller = new AbortController();
// Start fetch with signal
fetch('https://api.example.com/data', {
signal: controller.signal // ← Pass the signal
})
.then(response => response.json())
.then(data => {
console.log('Data received:', data);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('Fetch was cancelled!');
} else {
console.error('Fetch error:', error);
}
});
// Cancel the request after 2 seconds
setTimeout(() => {
controller.abort(); // ← Cancel!
console.log('Request aborted');
}, 2000);
// If fetch takes longer than 2 seconds, it gets cancelled
// Output: "Request aborted" then "Fetch was cancelled!"// Cancel previous search when user types new query
let currentController = null;
async function searchProducts(query) {
// Cancel previous search if still running
if (currentController) {
currentController.abort();
console.log('Cancelled previous search');
}
// Create new controller for this search
currentController = new AbortController();
try {
const response = await fetch(
`https://api.example.com/search?q=${query}`,
{ signal: currentController.signal }
);
const results = await response.json();
displayResults(results);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Search cancelled - user typed something new');
} else {
console.error('Search error:', error);
}
}
}
// User types in search box
searchProducts('laptop'); // Request 1 starts
searchProducts('laptop char'); // Request 1 cancelled, Request 2 starts
searchProducts('laptop charger'); // Request 2 cancelled, Request 3 starts
// Only the last search completes!
// 🎯 Benefit: Don't waste bandwidth on outdated searches// Reusable function to fetch with timeout
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
// Set timeout to abort
const timeoutId = setTimeout(() => {
controller.abort();
}, timeout);
try {
const response = await fetch(url, {
signal: controller.signal
});
clearTimeout(timeoutId); // Clear timeout if successful
return await response.json();
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error(`Request timeout after ${timeout}ms`);
}
throw error;
}
}
// Usage
try {
const data = await fetchWithTimeout(
'https://slow-api.example.com/data',
3000 // 3 second timeout
);
console.log('Data:', data);
} catch (error) {
console.error('Failed:', error.message);
}
// If request takes > 3 seconds: "Failed: Request timeout after 3000ms"// Load page with multiple API calls
async function loadDashboard() {
const controller = new AbortController();
const signal = controller.signal;
try {
// Start all requests in parallel
const [userData, postsData, commentsData] = await Promise.all([
fetch('https://api.example.com/user', { signal }),
fetch('https://api.example.com/posts', { signal }),
fetch('https://api.example.com/comments', { signal })
]);
const user = await userData.json();
const posts = await postsData.json();
const comments = await commentsData.json();
displayDashboard(user, posts, comments);
} catch (error) {
if (error.name === 'AbortError') {
console.log('Dashboard load cancelled');
} else {
console.error('Error loading dashboard:', error);
}
}
return controller; // Return so caller can abort
}
// Load dashboard
const dashboardController = await loadDashboard();
// User navigates away - cancel all requests at once!
window.addEventListener('beforeunload', () => {
dashboardController.abort(); // Cancels ALL 3 requests!
});
// 🎯 One controller can abort multiple operations// Custom async function that supports abort
async function processLargeFile(file, signal) {
const chunks = splitIntoChunks(file);
const results = [];
for (let i = 0; i < chunks.length; i++) {
// Check if aborted
if (signal?.aborted) {
throw new DOMException('Processing aborted', 'AbortError');
}
console.log(`Processing chunk ${i + 1}/${chunks.length}`);
// Simulate processing
await new Promise(resolve => setTimeout(resolve, 1000));
results.push(processChunk(chunks[i]));
// Listen for abort during processing
signal?.addEventListener('abort', () => {
throw new DOMException('Processing aborted', 'AbortError');
});
}
return results;
}
// Usage
const controller = new AbortController();
processLargeFile(myFile, controller.signal)
.then(results => {
console.log('Processing complete!', results);
})
.catch(error => {
if (error.name === 'AbortError') {
console.log('User cancelled processing');
}
});
// User clicks cancel button
document.getElementById('cancelBtn').addEventListener('click', () => {
controller.abort();
});
// 🎯 Your custom functions can support abort too!// Modern way: Create signal with timeout built-in
try {
const response = await fetch('https://api.example.com/data', {
signal: AbortSignal.timeout(5000) // Auto-abort after 5 seconds
});
const data = await response.json();
console.log(data);
} catch (error) {
if (error.name === 'TimeoutError' || error.name === 'AbortError') {
console.error('Request timed out!');
} else {
console.error('Fetch failed:', error);
}
}
// 🎯 Cleaner than manually creating controller + setTimeout!
// Can also combine multiple signals
const controller = new AbortController();
const combinedSignal = AbortSignal.any([
controller.signal, // Manual abort
AbortSignal.timeout(10000) // Or timeout
]);
fetch('https://api.example.com/data', { signal: combinedSignal });
// Aborts if EITHER condition happens:
// - You call controller.abort()
// - Or 10 seconds passCancel previous search when user types new query
Cancel ongoing requests when user leaves page
Abort requests that take too long
Let users cancel uploads in progress
Cancel loading next page if user scrolls back up
Handle AbortError separately from real errors
if (error.name === 'AbortError') {/* user cancelled */}Store references if you need to abort later, but don't keep old ones
In React: abort requests when component unmounts
useEffect(() => { return () => controller.abort(); }, []);You can use same controller for multiple related operations
Once aborted, create a new controller for next operation
Stop fetch, uploads, or
Any async task
Give controller.signal
To fetch or async function
controller.abort()
Cancels immediately
Perfect for autocomplete
Cancel old searches