There is a new API for making requests from JavaScript: fetch()
. Is there any built in mechanism for canceling these requests in-flight?
-
1can refer https://davidwalsh.name/cancel-fetch also – ganesh phirke May 30 '20 at 19:08
7 Answers
TL/DR:
fetch
now supports a signal
parameter as of 20 September 2017, but not
all browsers seem support this at the moment.
2020 UPDATE: Most major browsers (Edge, Firefox, Chrome, Safari, Opera, and a few others) support the feature, which has become part of the DOM living standard. (as of 5 March 2020)
This is a change we will be seeing very soon though, and so you should be able to cancel a request by using an AbortController
s AbortSignal
.
Long Version
How to:
The way it works is this:
Step 1: You create an AbortController
(For now I just used this)
const controller = new AbortController()
Step 2: You get the AbortController
s signal like this:
const signal = controller.signal
Step 3: You pass the signal
to fetch like so:
fetch(urlToFetch, {
method: 'get',
signal: signal, // <------ This is our AbortSignal
})
Step 4: Just abort whenever you need to:
controller.abort();
Here's an example of how it would work (works on Firefox 57+):
<script>
// Create an instance.
const controller = new AbortController()
const signal = controller.signal
/*
// Register a listenr.
signal.addEventListener("abort", () => {
console.log("aborted!")
})
*/
function beginFetching() {
console.log('Now fetching');
var urlToFetch = "https://httpbin.org/delay/3";
fetch(urlToFetch, {
method: 'get',
signal: signal,
})
.then(function(response) {
console.log(`Fetch complete. (Not aborted)`);
}).catch(function(err) {
console.error(` Err: ${err}`);
});
}
function abortFetching() {
console.log('Now aborting');
// Abort.
controller.abort()
}
</script>
<h1>Example of fetch abort</h1>
<hr>
<button onclick="beginFetching();">
Begin
</button>
<button onclick="abortFetching();">
Abort
</button>
Sources:
- The final version of AbortController has been added to the DOM specification
- The corresponding PR for the fetch specification is now merged.
- Browser bugs tracking the implementation of AbortController is available here: Firefox: #1378342, Chromium: #750599, WebKit: #174980, Edge: #13009916.
-
3This answer is correct and should be upvoted. But I took the liberty of making some edits to the code snippet, because as-is it wasn’t actually working in Firefox 57+ — the shim seemed to be causing it to fail (*“Err: TypeError: 'signal' member of RequestInit does not implement interface AbortSignal.”*) and there seems to be some problem with the cert for https://slowwly.robertomurray.co.uk/ (*“This server could not prove that it is slowwly.robertomurray.co.uk; its security certificate is from *.herokuapp.com.”*), so I changed it to just use http://slowwly.robertomurray.co.uk/ (plain http). – sideshowbarker Nov 23 '17 at 01:11
-
3But now it doesn't work on other browsers i.e Chrome because `AbortController is not defined`. Anyway this is just a proof of concept, at least people with Firefox 57+ can see it working – SudoPlz Nov 25 '17 at 09:15
-
6This is pure StackOverflow gold, thanks for the concise writeup! And the bugtracker links as well! – Kjellski Apr 11 '18 at 06:58
-
6Now all modern browsers support it. https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort see table in the bottom – Alex Ivasyuv Jul 11 '18 at 08:21
-
@AlexIvasyuv - it doesn't matter who support what *now*. I am writing code that might run on a 1-2 year old Chrome machine, and I need to make sure it works. rarely I have the privilege to only care about **now** – vsync Oct 01 '18 at 15:25
-
Remember when angular first came out, the only way to abort requests was by resolving (or was it rejecting?) promises passed in to the request as another parameter. Seriously, how hard is it to add a freaking "abort" method to the API, just because die-hards want `fetch` to return exactly a promise. `then`, `catch` and `abort` seem like reasonable methods to be returned on the `FetchPromise` People are going to be writing libraries that have this API anyway, so why not just make it so? – Adam Jenkins Nov 08 '18 at 17:09
-
In google chrome, it didn't work if I imported the linked NPM module, only when I removed the NPM module and used the browsers build in classes it started working – Ferrybig Nov 14 '18 at 13:03
-
7Thanks but I still have a question, should we change the signal back to true for the next fetch manually?? – akshay kishore Feb 21 '19 at 12:51
-
1best answer, before seeing this, I was reading 2000 words tutorial about abort, and got confused as hell, now it so easy. Why not all tutorial look like like this? – angry kiwi Aug 11 '19 at 19:10
-
1If you want polyfills to support AbortController, Promises, and fetch on older browsers, you can use [mo/abortcontroller-polyfill](https://github.com/mo/abortcontroller-polyfill) with [taylorhakes/promise-polyfill](https://github.com/taylorhakes/promise-polyfill) and [github/fetch](https://github.com/github/fetch). – Quinn Comendant Oct 11 '19 at 01:39
-
1@SudoPlz What does this look like when using ES7 `async/await` syntax? I feel like all the examples of this have been using ES6 promises and we should be forward looking. – Danchez Jul 10 '20 at 17:00
-
2@akshaykishore Once an instance of AbortController is used, we need to create a new instance to reset the value. https://dev.to/beejluig/cancel-fetch-with-abortcontroller-2435 – Ivan Bacher Sep 16 '20 at 12:27
-
1
https://developers.google.com/web/updates/2017/09/abortable-fetch
https://dom.spec.whatwg.org/#aborting-ongoing-activities
// setup AbortController
const controller = new AbortController();
// signal to pass to fetch
const signal = controller.signal;
// fetch as usual
fetch(url, { signal }).then(response => {
...
}).catch(e => {
// catch the abort if you like
if (e.name === 'AbortError') {
...
}
});
// when you want to abort
controller.abort();
works in edge 16 (2017-10-17), firefox 57 (2017-11-14), desktop safari 11.1 (2018-03-29), ios safari 11.4 (2018-03-29), chrome 67 (2018-05-29), and later.
on older browsers, you can use github's whatwg-fetch polyfill and AbortController polyfill. you can detect older browsers and use the polyfills conditionally, too:
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
import {fetch} from 'whatwg-fetch'
// use native browser implementation if it supports aborting
const abortableFetch = ('signal' in new Request('')) ? window.fetch : fetch

- 5,653
- 2
- 44
- 65
-
If using github's fetch polyfill, this is possible to do with it, just follow the instructions on their readme: https://github.com/github/fetch#aborting-requests – Fábio Santos Mar 12 '19 at 15:33
-
@FábioSantos Should your comment be on the question, or as an answer in it's own right? It doesn't look specific to my answer. – Jayen Mar 12 '19 at 22:19
-
Just a note for people who are using the github fetch polyfill. I thought it was relevant to your answer because AFAIK it's the most popular fetch polyfill available, and it polyfills the function you're using, fetch. A lot of people will be using this polyfill because of old browsers. I found it important to mention because people just assume polyfills fix everything, but this particular one doesn't try to polyfill AbortController. They'd try to use AbortController thinking it's going to be polyfilled in old browsers, and boom, there's an exception in a corner case and only on old browsers. – Fábio Santos Mar 13 '19 at 17:27
As of Feb 2018, fetch()
can be cancelled with the code below on Chrome (read Using Readable Streams to enable Firefox support). No error is thrown for catch()
to pick up, and this is a temporary solution until AbortController
is fully adopted.
fetch('YOUR_CUSTOM_URL')
.then(response => {
if (!response.body) {
console.warn("ReadableStream is not yet supported in this browser. See https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream")
return response;
}
// get reference to ReadableStream so we can cancel/abort this fetch request.
const responseReader = response.body.getReader();
startAbortSimulation(responseReader);
// Return a new Response object that implements a custom reader.
return new Response(new ReadableStream(new ReadableStreamConfig(responseReader)));
})
.then(response => response.blob())
.then(data => console.log('Download ended. Bytes downloaded:', data.size))
.catch(error => console.error('Error during fetch()', error))
// Here's an example of how to abort request once fetch() starts
function startAbortSimulation(responseReader) {
// abort fetch() after 50ms
setTimeout(function() {
console.log('aborting fetch()...');
responseReader.cancel()
.then(function() {
console.log('fetch() aborted');
})
},50)
}
// ReadableStream constructor requires custom implementation of start() method
function ReadableStreamConfig(reader) {
return {
start(controller) {
read();
function read() {
reader.read().then(({done,value}) => {
if (done) {
controller.close();
return;
}
controller.enqueue(value);
read();
})
}
}
}
}

- 8,245
- 2
- 28
- 53
-
2This is NOT what the OP was asking for. They want to cancel the fetch not the reader. Fetch's promise does not resolve until AFTER the request has finished, which is too late to cancel the request to the server. – Rahly Aug 18 '18 at 23:31
Let's polyfill:
if(!AbortController){
class AbortController {
constructor() {
this.aborted = false;
this.signal = this.signal.bind(this);
}
signal(abortFn, scope) {
if (this.aborted) {
abortFn.apply(scope, { name: 'AbortError' });
this.aborted = false;
} else {
this.abortFn = abortFn.bind(scope);
}
}
abort() {
if (this.abortFn) {
this.abortFn({ reason: 'canceled' });
this.aborted = false;
} else {
this.aborted = true;
}
}
}
const originalFetch = window.fetch;
const customFetch = (url, options) => {
const { signal } = options || {};
return new Promise((resolve, reject) => {
if (signal) {
signal(reject, this);
}
originalFetch(url, options)
.then(resolve)
.catch(reject);
});
};
window.fetch = customFetch;
}
Please have in mind that the code is not tested! Let me know if you have tested it and something didn't work. It may give you warnings that you try to overwrite the 'fetch' function from the JavaScript official library.

- 1,432
- 1
- 18
- 39
As for now there is no proper solution, as @spro says.
However, if you have an in-flight response and are using ReadableStream, you can close the stream to cancel the request.
fetch('http://example.com').then((res) => {
const reader = res.body.getReader();
/*
* Your code for reading streams goes here
*/
// To abort/cancel HTTP request...
reader.cancel();
});

- 159,648
- 54
- 349
- 530
This works in browser and nodejs Live browser demo
const cpFetch= require('cp-fetch');
const url= 'https://run.mocky.io/v3/753aa609-65ae-4109-8f83-9cfe365290f0?mocky-delay=3s';
const chain = cpFetch(url, {timeout: 10000})
.then(response => response.json())
.then(data => console.log(`Done: `, data), err => console.log(`Error: `, err))
setTimeout(()=> chain.cancel(), 1000); // abort the request after 1000ms

- 1,419
- 2
- 8
- 7
Easy typescripted version (fetch gets aborted):
export async function fetchWithTimeout(url: RequestInfo, options?: RequestInit, timeout?: number) {
return new Promise<Response>((resolve, reject) => {
const controller = new AbortController();
const signal = controller.signal;
const timeoutId = setTimeout(() => {
console.log('TIMEOUT');
reject('Timeout');
// Cancel fetch in progress
controller.abort();
}, timeout ?? 5 * 1000);
fetch(url, { ...options, signal })
.then((response) => {
clearTimeout(timeoutId);
resolve(response);
})
.catch((e) => reject(e));
});
}
Maybe you need a polyfill (e.g. IE11):
https://polyfill.io/v3/polyfill.min.js?features=AbortController

- 130
- 12