Réponses:
fetch
prend désormais en charge un signal
paramètre au 20 septembre 2017, mais tous les navigateurs ne semblent pas le prendre en charge pour le moment .
MISE À JOUR 2020: La plupart des principaux navigateurs (Edge, Firefox, Chrome, Safari, Opera et quelques autres) prennent en charge la fonctionnalité , qui fait désormais partie du standard de vie DOM . (au 5 mars 2020)
C'est un changement que nous verrons très bientôt cependant, et vous devriez donc être en mesure d'annuler une demande en utilisant un AbortController
s AbortSignal
.
Voici comment cela fonctionne:
Etape 1 : Vous créez un AbortController
(Pour l' instant , je viens d' utiliser ce )
const controller = new AbortController()
Étape 2 : Vous obtenez le AbortController
signal s comme ceci:
const signal = controller.signal
Étape 3 : Vous passez le signal
pour récupérer comme ceci:
fetch(urlToFetch, {
method: 'get',
signal: signal, // <------ This is our AbortSignal
})
Étape 4 : abandonnez simplement chaque fois que vous devez:
controller.abort();
Voici un exemple de la façon dont cela fonctionnerait (fonctionne sur 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
. Quoi qu'il en soit, ce n'est qu'une preuve de concept, au moins les gens avec Firefox 57+ peuvent le voir fonctionner
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();
fonctionne dans 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), et plus tard.
sur les navigateurs plus anciens, vous pouvez utiliser le polyfill whatwg-fetch de github et le polyfill AbortController . vous pouvez détecter les anciens navigateurs et utiliser également les polyfills de manière conditionnelle :
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
À partir de février 2018, fetch()
peut être annulé avec le code ci-dessous sur Chrome (lire Utilisation de flux lisibles pour activer la prise en charge de Firefox). Aucune erreur n'est levée pour catch()
le ramassage, et c'est une solution temporaire jusqu'à ce qu'elle AbortController
soit complètement adoptée.
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();
})
}
}
}
}
Pour l'instant, il n'y a pas de solution appropriée, comme le dit @spro.
Cependant, si vous avez une réponse en vol et utilisez ReadableStream, vous pouvez fermer le flux pour annuler la demande.
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();
});
Faisons 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;
}
N'oubliez pas que le code n'est pas testé! Faites-moi savoir si vous l'avez testé et que quelque chose n'a pas fonctionné. Il peut vous avertir que vous essayez d'écraser la fonction «récupérer» de la bibliothèque officielle JavaScript.