Cleaning up fetch requests with the Abort Controller Web API
3 min read · 1 year ago


Hello everyone, i just wanted to share a little something i learned this week, the Abort Controller API.
What is it and what does it do?
The AbortController API in JavaScript allows you to cancel ongoing asynchronous tasks, such as fetch requests, before they complete. It gives you the ability to stop asynchronous tasks that are still in progress, like a fetch request to an external API, before they finish. This can be helpful in a number of situations:
- Users make quick changes (e.g, in a search box) and previous requests are no longer relevant.
- You need to prevent memory or network overhead by stopping tasks that no longer serve a purpose.
- You want to ensure that certain processes (like fetching) don’t continue running after a component unmounts in a React app.
Now in this article, we are going to learn how we can solve all three above mentioned issues with the Abort Controller API.
A common scenario in react
Imagine a fetch request inside a useEffect hook in a React app. The hook depends on a query state, which updates each time the user types in an input field. This triggers the useEffect and starts a new fetch request.
However, this causes a few problems:
- A fetch request is triggered on every keystroke
- Without intervention, all requests run in parallel, creating multiple unnecessary requests, slowing down the app, and causing network overhead and race conditions.
The solution? The AbortController API
The key elements of the Abort Controller API include:
- AbortController: The core object that creates and manages the abort signal.
1const controller = new AbortController();- AbortSignal: A signal produced by the controller, which is passed to functions like
fetchto enable cancellation. This is passed as an argument to the fetch alongside the fetch URL.
1{ signal: controller.signal }- abort() method: This method on the
AbortControllertriggers the cancellation, sending a signal to the operation that should be stopped. This is used as a cleanup function.
1function () {
2 controller.abort();
3 }Now i will demonstrate using this in practice showing what our network tab looks like before and after using the AbortController.
Without the AbortController API
1useEffect(
2 function () {
3 async function fetchMovies() {
4 try {
5 setIsLoading(true);
6 setErrorMessage("");
7 const res = await fetch(
8 `http://www.omdbapi.com/?apikey=${KEY}&s=${query}`
9 );
10
11 if (!res.ok) throw new Error("Something went wrong");
12
13 const data = await res.json();
14
15 if (data.Response === "False") throw new Error("Movie not found!");
16 setMovies(data.Search);
17 setErrorMessage("");
18 } catch (err) {
19 setErrorMessage(err.message);
20 } finally {
21 setIsLoading(false);
22 }
23 }
24
25 if (query.length < 3) {
26 setMovies([]);
27 setErrorMessage("");
28 return;
29 }
30
31 fetchMovies();
32 },
33 [query]
34 );here, we can see every keystroke runs a fetch request

In this version, every time the user types, a new fetch request is initiated. This results in unnecessary requests for every partial query like s, sp, spi, etc., when the user is really searching for spiderman
With the AbortController API
1useEffect(
2 function () {
3 const controller = new AbortController();
4 async function fetchMovies() {
5 try {
6 setIsLoading(true);
7 setErrorMessage("");
8 const res = await fetch(
9 `http://www.omdbapi.com/?apikey=${KEY}&s=${query}`,
10 { signal: controller.signal }
11 );
12
13 if (!res.ok) throw new Error("Something went wrong");
14
15 const data = await res.json();
16
17 if (data.Response === "False") throw new Error("Movie not found!");
18 setMovies(data.Search);
19 setErrorMessage("");
20 } catch (err) {
21 if (err.name !== "AbortError") setErrorMessage(err.message);
22 } finally {
23 setIsLoading(false);
24 }
25 }
26
27 if (query.length < 3) {
28 setMovies([]);
29 setErrorMessage("");
30 return;
31 }
32
33 fetchMovies();
34
35 return function () {
36 controller.abort();
37 };
38 },
39 [query]
40 );here, we can see only the latest request is fetched, the others are cancelled

With the AbortController, we cancel any previous fetch request when the user makes a new input, preventing unnecessary data from being fetched. Only the latest request is processed, improving performance and avoiding race conditions.
Result
When we compare both versions:
- Without AbortController: Each keystroke results in a fetch request, retrieving unnecessary data and consuming more resources.
- With AbortController: Only the final query (e.g., “spiderman”) is fetched. The previous incomplete queries are aborted, preventing extra network overhead.
By using AbortController, you can efficiently manage fetch requests in a React app, ensuring only the relevant data is fetched and network resources aren’t wasted.
This was a small insight into how the AbortController API can clean up your async operations in JavaScript! Hope this helps. Thanks for reading!
Hello everyone, i just wanted to share a little something i learned this week, the Abort Controller API.
What is it and what does it do?
The AbortController API in JavaScript allows you to cancel ongoing asynchronous tasks, such as fetch requests, before they complete. It gives you the ability to stop asynchronous tasks that are still in progress, like a fetch request to an external API, before they finish. This can be helpful in a number of situations:
- Users make quick changes (e.g, in a search box) and previous requests are no longer relevant.
- You need to prevent memory or network overhead by stopping tasks that no longer serve a purpose.
- You want to ensure that certain processes (like fetching) don’t continue running after a component unmounts in a React app.
Now in this article, we are going to learn how we can solve all three above mentioned issues with the Abort Controller API.
A common scenario in react
Imagine a fetch request inside a useEffect hook in a React app. The hook depends on a query state, which updates each time the user types in an input field. This triggers the useEffect and starts a new fetch request.
However, this causes a few problems:
- A fetch request is triggered on every keystroke
- Without intervention, all requests run in parallel, creating multiple unnecessary requests, slowing down the app, and causing network overhead and race conditions.
The solution? The AbortController API
The key elements of the Abort Controller API include:
- AbortController: The core object that creates and manages the abort signal.
1const controller = new AbortController();- AbortSignal: A signal produced by the controller, which is passed to functions like
fetchto enable cancellation. This is passed as an argument to the fetch alongside the fetch URL.
1{ signal: controller.signal }- abort() method: This method on the
AbortControllertriggers the cancellation, sending a signal to the operation that should be stopped. This is used as a cleanup function.
1function () {
2 controller.abort();
3 }Now i will demonstrate using this in practice showing what our network tab looks like before and after using the AbortController.
Without the AbortController API
1useEffect(
2 function () {
3 async function fetchMovies() {
4 try {
5 setIsLoading(true);
6 setErrorMessage("");
7 const res = await fetch(
8 `http://www.omdbapi.com/?apikey=${KEY}&s=${query}`
9 );
10
11 if (!res.ok) throw new Error("Something went wrong");
12
13 const data = await res.json();
14
15 if (data.Response === "False") throw new Error("Movie not found!");
16 setMovies(data.Search);
17 setErrorMessage("");
18 } catch (err) {
19 setErrorMessage(err.message);
20 } finally {
21 setIsLoading(false);
22 }
23 }
24
25 if (query.length < 3) {
26 setMovies([]);
27 setErrorMessage("");
28 return;
29 }
30
31 fetchMovies();
32 },
33 [query]
34 );here, we can see every keystroke runs a fetch request

In this version, every time the user types, a new fetch request is initiated. This results in unnecessary requests for every partial query like s, sp, spi, etc., when the user is really searching for spiderman
With the AbortController API
1useEffect(
2 function () {
3 const controller = new AbortController();
4 async function fetchMovies() {
5 try {
6 setIsLoading(true);
7 setErrorMessage("");
8 const res = await fetch(
9 `http://www.omdbapi.com/?apikey=${KEY}&s=${query}`,
10 { signal: controller.signal }
11 );
12
13 if (!res.ok) throw new Error("Something went wrong");
14
15 const data = await res.json();
16
17 if (data.Response === "False") throw new Error("Movie not found!");
18 setMovies(data.Search);
19 setErrorMessage("");
20 } catch (err) {
21 if (err.name !== "AbortError") setErrorMessage(err.message);
22 } finally {
23 setIsLoading(false);
24 }
25 }
26
27 if (query.length < 3) {
28 setMovies([]);
29 setErrorMessage("");
30 return;
31 }
32
33 fetchMovies();
34
35 return function () {
36 controller.abort();
37 };
38 },
39 [query]
40 );here, we can see only the latest request is fetched, the others are cancelled

With the AbortController, we cancel any previous fetch request when the user makes a new input, preventing unnecessary data from being fetched. Only the latest request is processed, improving performance and avoiding race conditions.
Result
When we compare both versions:
- Without AbortController: Each keystroke results in a fetch request, retrieving unnecessary data and consuming more resources.
- With AbortController: Only the final query (e.g., “spiderman”) is fetched. The previous incomplete queries are aborted, preventing extra network overhead.
By using AbortController, you can efficiently manage fetch requests in a React app, ensuring only the relevant data is fetched and network resources aren’t wasted.
This was a small insight into how the AbortController API can clean up your async operations in JavaScript! Hope this helps. Thanks for reading!