How to Cancel a Fetch Request
JavaScript promises have always been a major win for the language -- they've led to a revolution of asynchronous coding that has vastly improved performance on the web. One shortcoming of native promises is that there's no true way to cancel a fetch
...until now. A new AbortController
has been added to the JavaScript specification that will allow developers to use a signal to abort one or multiple fetch calls.
Here's the flow of how canceling a fetch
call works:
- Create an
AbortController
instance - That instance has a
signal
property - Pass the
signal
as a fetch option forsignal
- Call the
AbortController
'sabort
property to cancel all fetches that use that signal.
Aborting a Fetch
The following is the bare bones of canceling a fetch request:
const controller = new AbortController(); const { signal } = controller; fetch("http://localhost:8000", { signal }).then(response => { console.log(`Request 1 is complete!`); }).catch(e => { console.warn(`Fetch 1 error: ${e.message}`); }); // Abort request controller.abort();
An AbortError
occurs upon the abort
call, so you can listen for aborted fetches in the catch
by comparing the error name:
}).catch(e => { if(e.name === "AbortError") { // We know it's been canceled! } });
Passing the same signal to multiple fetch
calls will cancel all requests with that signal:
const controller = new AbortController(); const { signal } = controller; fetch("http://localhost:8000", { signal }).then(response => { console.log(`Request 1 is complete!`); }).catch(e => { console.warn(`Fetch 1 error: ${e.message}`); }); fetch("http://localhost:8000", { signal }).then(response => { console.log(`Request 2 is complete!`); }).catch(e => { console.warn(`Fetch 2 error: ${e.message}`); }); // Wait 2 seconds to abort both requests setTimeout(() => controller.abort(), 2000);
In his article Abortable fetch, Jake Archibald details a nice utility for creating abortable fetches without the need for all of the boilerplate:
function abortableFetch(request, opts) { const controller = new AbortController(); const signal = controller.signal; return { abort: () => controller.abort(), ready: fetch(request, { ...opts, signal }) }; }
If I'm completely honest, I'm not super excited about the method for canceling fetches. In an ideal world, a basic .cancel()
on the Promise returned by a fetch would be cool, but there are issues that would come with that too. In any event, I'm jazzed about being able to cancel fetch
calls and you should be too!
I would love to know what happens under the hood: is the cancellation handled only locally, does it involve some action toward the server?
I tried to cancel a request a while ago and decided it was easier to ignore the response when it arrives.
connection is closed and that’s it. Server may handle that case in the middle of processing request or may go till the very end to realize response it’s not needed anymore. It’s up to backend-side implementation.
So jazzed right now. Thanks David!
Next article: “How to Show Upload Progress with the Fetch API”.
This is exactly what I was looking for. I’m currently trying to upgrade some old jQuery code (specifically
$.ajax()
) and was looking for how to cancel the call the way I could with jQuery. Hopefully it’s supported everywherefetch()
is supported. To be honest, I’m used to having to think about this. Using ES5+jQuery for _so long_, compatibility was rarely ever an issue.