Canceling Fetch Requests in JavaScript: A Step-by-Step Guide

Learn how to cancel ongoing fetch requests in JavaScript to optimize network performance

Danielle Dias
Geek Culture

--

Photo by Pedro Sanz on Unsplash

JavaScript provides a built-in Fetch API that simplifies the process of making these requests. However, there are instances when we need to cancel a fetch request due to various reasons such as user interaction or changes in application state. In this article, we will explore different approaches to canceling a fetch request effectively.

Using the AbortController API

One effective approach to canceling fetch requests is by utilizing the AbortController API. Introduced as part of the Fetch API, the AbortController allows us to programmatically cancel ongoing requests. To demonstrate its usage, consider the following code snippet:

// Create an AbortController instance
const controller = new AbortController();

// Obtain a reference to the AbortSignal
const signal = controller.signal;
// Make a fetch request with the signal
fetch('https://api.example.com/data', { signal })
.then(response => {
// Handle the response
})
.catch(error => {
// Handle errors
});
// To cancel the request, call the abort() method on the controller
controller.abort();

In the code above, we first create an instance of the AbortController and obtain a reference to the associated AbortSignal. We pass this signal as an option in the fetch request configuration. If we decide to cancel the request, we simply call the abort() method on the controller.

When the request is canceled, the fetch Promise will be rejected with an AbortError. To handle this scenario, we can utilize the catch() method to provide appropriate error handling.

Reacting to Canceled Requests

Now that we know how to cancel a fetch request, let’s explore how we can react to the cancellation in our code. One way to achieve this is by using the finally() method, which allows us to execute cleanup logic regardless of whether the request was successful or canceled. Consider the following example:

fetch('https://api.example.com/data', { signal })
.then(response => {
// Handle the response
})
.catch(error => {
if (error.name === 'AbortError') {
// Handle cancellation
} else {
// Handle other errors
}
})
.finally(() => {
// Cleanup logic
});

In the code snippet above, we added a catch() block to handle the AbortError specifically. This allows us to differentiate between a canceled request and other types of errors that might occur during the fetch process. The finally() method is then used to execute any necessary cleanup logic, such as resetting UI states or releasing resources.

Improving UX with Debouncing

In certain scenarios, canceling a fetch request might be triggered by user interaction, such as typing in a search box or filtering data. To optimize the user experience and reduce unnecessary requests, we can employ a technique called debouncing.

Debouncing involves introducing a small delay before sending a request, allowing the user to finish their input before initiating the fetch. If the user continues typing within the delay period, the previous request is canceled, and a new one is scheduled. This prevents excessive requests and ensures that only the final request, after the delay, is executed.

Let’s take a look at a code example demonstrating how debouncing can be implemented:

let debounceTimer;

function makeFetchRequest(query) {
// Clear the previous debounce timer
clearTimeout(debounceTimer);
// Set a new timer to execute the fetch request after a delay
debounceTimer = setTimeout(() => {
// Create an AbortController instance
const controller = new AbortController();
// Obtain a reference to the AbortSignal
const signal = controller.signal;
fetch(`https://api.example.com/search?q=${query}`, { signal })
.then(response => {
// Handle the response
})
.catch(error => {
if (error.name === 'AbortError') {
// Handle cancellation
} else {
// Handle other errors
}
})
.finally(() => {
// Cleanup logic
});
// To cancel the request, call the abort() method on the controller
// For example, if the user clears the search query
// controller.abort();
}, 300); // Set a delay of 300 milliseconds
}

// Example usage in an input event listener
const searchInput = document.getElementById('search-input');
searchInput.addEventListener('input', event => {
const query = event.target.value;
makeFetchRequest(query);
});

In the code snippet above, we utilize the setTimeout() function to introduce a delay of 300 milliseconds before executing the fetch request. If the user continues typing within this delay period, the previous debounce timer is cleared, and a new timer is set. This ensures that the fetch request is only made once the user has paused their input for the specified delay.

Within the debounce timer’s callback function, we create an instance of the AbortController and pass its associated AbortSignal to the fetch request. This allows us to cancel the request if needed, such as when the user clears the search query.

Remember to adjust the delay value (300 milliseconds in this example) according to your specific use case and desired user experience.

Conclusion

In this article, we explored the usage of the AbortController API, which allows us to programmatically cancel ongoing fetch requests. We also discussed how to react to canceled requests using the finally() method and provided examples of debouncing to optimize user interaction and prevent excessive requests.

Thanks for reading. If you enjoyed this article, consider supporting me by becoming a Medium member.

--

--