How do I cancel an HTTP fetch() request?
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>
How to cancel previous fetch request in new fetch request in react?
I found a way to cancel the previous request and accept only the response from the latest request. I am using redux-thunk as the middleware. I can use a controller as AbortController and send a signal to the fetch request and then I can cancel the previous request using this controller.
return (dispatch, getState, serviceManager) => {
const { controller } = getState();
controller.abort(); //cancel the previous request
let newController = new AbortController();
let signal = newController.signal;
//set a new AbortController instance to the reducer
dispatch({type: "SET_NEW_CONTROLLER", payload: newController})
//pass the signal to the fetch request
const result = await fetch(url, {...options, signal});
}
Abort a JS fetch() after request is sent and before the wait/download time
if you want to send a request but don't need the body of the reply you should send using HEAD method, this instructs the server to just reply with the headers of the call and not the body, so you can check for a status or content type etc that is in the header package
send 10 requests as fast as possible then await the reponses
const pending=[];
for(let i=0;i<10:i++)
{
pending.push(fetch(url, {method:"HEAD"});
}
for(const req of pending){
const res = await req;
//check for a 200 code or any other bodyless data
}
or if you really don't care about the response as all there is no need to await the promise completion
for(let i=0;i<10:i++)
{
fetch(url, {method:"HEAD"});
}
aborting is for when you want to terminate the call even if it hasn't been sent
as mentions by @Bergi , if you just want to ping the url then you can use
navigator.sendBeacon(url)
but this will send a post request giving you much less control of what you do with the request
How do I abort fetch request and start a new one immediately?
Not sure if I got it clearly, but from what I understand, your case is not different no.
The basics are the same, store the controller somewhere accessible to your logic that may cancel it, and cancel it if needed, before sending the new request:
let aborter = null; // make the aborter accessiblefunction getData(param) { // cancel pending request if any if(aborter) aborter.abort(); // make our request cancellable aborter = new AbortController(); const signal = aborter.signal; const url = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png?rand=' + param; return fetch(url, {signal}) // clean up, not really needed but may help to know if there is a pending request .then(r => {aborter = null; return r;})}// first request will get abortedgetData("foo") .then(r => console.log('foo done')) .catch(e => console.error('foo failed', e.name, e.message));// will abort the previous onegetData("bar") .then(r => console.log('bar done')) .catch(e => console.error('bar failed', e.name, e.message))
How to abort fetching HTTP request using AbortController on the same button
It is because you call the controller.abort() on different instance than you initialized signal.
What about something like this?
let isLoading = false;
let controller = new AbortController();
const abort = () => controller.abort();
const button = document.getElementById("test");
const fetchData = () => {
if (isLoading) {
abort();
controller = new AbortController();
}
isLoading = true;
return fetch('https://jsonplaceholder.typicode.com/todos', {
signal: controller.signal
})
.catch(e => {
console.warn(`Fetch 1 error: ${e.message}`);
})
.finally(() => isLoading = false);
}
button.addEventListener('click', () => {
fetchData();
});
How to abort a fetch request?
Its still an open issue
All relevant discussion can be found here
https://github.com/whatwg/fetch/issues/447
:(
how to cancel the earlier fetch request and keep the last one during search
You are using the same controller/signal in all requests, you can save the previous controller like this :
const Search = ({ searchSuggestion }) => {
const previousController = useRef();
const onkeychange = async (e) => {
if (previousController.current) {
previousController.current.abort();
}
let string = e.target.value
const controller = new AbortController()
const signal = controller.signal
previousController.current = controller;
const suggest = await getSearchSuggestion({
string,
signal,
})
}
return (
<input
type="text"
autoComplete="off"
placeholder="Search"
className="search"
onChange={onkeychange}
/>
)
}
Related Topics
What's the Significant Use of Unary Plus and Minus Operators
How to Access Svg Elements with JavaScript
How to Display Length of Filtered Ng-Repeat Data
Jquery - Setting the Selected Value of a Select Control via Its Text Description
Define Global Variable with Webpack
How to Filter an Array from All Elements of Another Array
Is the Underscore Prefix for Property and Method Names Merely a Convention
Convert JSON Array to an HTML Table in Jquery
Underscore Template Throwing Variable Not Defined Error
How to Sort 2 Dimensional Array by Column Value
Es6 Modules: Export Single Class of Static Methods or Multiple Individual Methods
How to Format Time Since Xxx E.G. "4 Minutes Ago" Similar to Stack Exchange Sites
Regular Expression to Get a String Between Parentheses in JavaScript
React/Jsx Dynamic Component Name