JAVASCRIPT
Efficient API Request Cancellation with AbortController
Learn how to gracefully cancel pending API requests in JavaScript using AbortController to prevent race conditions and improve performance in single-page applications.
class ApiClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
this.activeControllers = new Map();
}
async get(endpoint, controllerId = null) {
const controller = new AbortController();
if (controllerId) {
// If there's an existing request for this ID, abort it
if (this.activeControllers.has(controllerId)) {
this.activeControllers.get(controllerId).abort();
}
this.activeControllers.set(controllerId, controller);
}
try {
const response = await fetch(`${this.baseUrl}/${endpoint}`, { signal: controller.signal });
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
if (error.name === 'AbortError') {
console.log('Request aborted:', controllerId);
} else {
console.error('API request failed:', error);
}
throw error;
} finally {
if (controllerId) {
this.activeControllers.delete(controllerId);
}
}
}
// Example usage in a UI component
// const client = new ApiClient('https://api.example.com');
// const searchInput = document.getElementById('search-input');
// searchInput.addEventListener('input', debounce(async (event) => {
// const query = event.target.value;
// if (!query) return;
// try {
// const data = await client.get(`search?q=${query}`, 'search-query');
// console.log('Search results:', data);
// } catch (error) {
// // Handle aborted requests gracefully
// if (error.name !== 'AbortError') {
// console.error('Failed to fetch search results:', error);
// }
// }
// }, 300));
}
How it works: This snippet demonstrates how to use the `AbortController` API to cancel ongoing `fetch` requests. A `ApiClient` class manages active controllers by `controllerId`. If a new request comes in with the same `controllerId` while a previous one is still pending, the old request is aborted before the new one starts. This is crucial for scenarios like search inputs where users type quickly, preventing multiple outdated responses from processing and reducing unnecessary network traffic. The `finally` block ensures cleanup of the active controller map.