Risposte:
fetch
ora supporta un signal
parametro dal 20 settembre 2017, ma al momento non tutti i browser sembrano supportarlo .
AGGIORNAMENTO 2020: la maggior parte dei principali browser (Edge, Firefox, Chrome, Safari, Opera e pochi altri) supportano la funzione , che è diventata parte dello standard di vita DOM . (a partire dal 5 marzo 2020)
Questa è una modifica che vedremo molto presto, quindi dovresti essere in grado di annullare una richiesta usando una AbortController
s AbortSignal
.
Il modo in cui funziona è questo:
Fase 1 : Si crea un AbortController
(per ora ho appena usato questo )
const controller = new AbortController()
Passaggio 2 : ricevi il AbortController
segnale s in questo modo:
const signal = controller.signal
Passaggio 3 : passi il signal
per recuperare in questo modo:
fetch(urlToFetch, {
method: 'get',
signal: signal, // <------ This is our AbortSignal
})
Passaggio 4 : basta interrompere ogni volta che è necessario:
controller.abort();
Ecco un esempio di come funzionerebbe (funziona su 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>
AbortController is not defined
. Comunque questa è solo una prova di concetto, almeno le persone con Firefox 57+ possono vederlo funzionare
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();
funziona 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) e versioni successive.
sui browser meno recenti, è possibile utilizzare il polyfill whatwg-fetch di github e il polyfill AbortController . puoi rilevare i browser più vecchi e utilizzare i polyfill anche in modo condizionale :
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
A partire da febbraio 2018, fetch()
può essere annullato con il codice riportato di seguito su Chrome (leggi Utilizzo dei flussi leggibili per abilitare il supporto di Firefox). Non viene generato alcun errore per la catch()
raccolta, e questa è una soluzione temporanea fino a quando non AbortController
viene completamente adottata.
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();
})
}
}
}
}
Per ora non esiste una soluzione adeguata, come dice @spro.
Tuttavia, se si dispone di una risposta in volo e si utilizza ReadableStream, è possibile chiudere lo stream per annullare la richiesta.
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();
});
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;
}
Tieni presente che il codice non è stato testato! Fammi sapere se l'hai provato e qualcosa non ha funzionato. Potrebbe darti avvisi che provi a sovrascrivere la funzione 'fetch' dalla libreria ufficiale JavaScript.