How to Cancel an Http Fetch() Request

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 AbortControllers 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 AbortControllers 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



Leave a reply



Submit