Comme nous le savons, fetch renvoie une promesse. Et JavaScript nâa gĂ©nĂ©ralement aucun concept dââannulationâ dâune promesse. Alors, comment pouvons-nous annuler un fetch en cours ? Par exemple. si les actions de lâutilisateur sur notre site indiquent que le fetch nâest plus nĂ©cessaire.
Il existe un objet intĂ©grĂ© spĂ©cial dĂ©diĂ© : AbortController, qui peut ĂȘtre utilisĂ© pour abandonner non seulement un fetch, mais aussi dâautres tĂąches asynchrones.
Lâutilisation est assez simple :
Lâobjet AbortController
Créez un contrÎleur :
let controller = new AbortController();
Un contrĂŽleur est un objet extrĂȘmement simple.
- Il a une seule méthode
abort(), - Et une seule propriété
signalqui permet de dĂ©finir des Ă©couteurs dâĂ©vĂ©nements dessus.
Quand abort() est appelé :
controller.signalĂ©met lâĂ©vĂ©nement"abort".- La propriĂ©tĂ©
controller.signal.aborteddevienttrue.
Generally, we have two parties in the process:
- The one that performs a cancelable operation, it sets a listener on
controller.signal. - The one that cancels: it calls
controller.abort()when needed.
Voici lâexemple complet (sans fetch encore) :
let controller = new AbortController();
let signal = controller.signal;
// The party that performs a cancelable operation
// gets the "signal" object
// and sets the listener to trigger when controller.abort() is called
signal.addEventListener('abort', () => alert("abort!"));
// The other party, that cancels (at any point later):
controller.abort(); // abort!
// L'événement se déclenche et signal.aborted devient vrai
alert(signal.aborted); // true
As we can see, AbortController is just a mean to pass abort events when abort() is called on it.
Nous pourrions implĂ©menter le mĂȘme type dâĂ©coute dâĂ©vĂ©nement dans notre code par nous-mĂȘmes, sans objet AbortController.
Mais ce qui est prĂ©cieux, câest que fetch sait comment travailler avec lâobjet AbortController, il est intĂ©grĂ© avec lui.
Utilisation avec fetch
Pour pouvoir annuler fetch, passez la propriĂ©tĂ© signal dâun AbortController comme une option fetch :
let controller = new AbortController();
fetch(url, {
signal: controller.signal
});
La méthode fetch sait comment travailler avec AbortController. Il écoutera les événements abort sur signal.
Maintenant, pour abandonner, appelons controller.abort() :
controller.abort();
Nous avons terminĂ©: fetch rĂ©cupĂšre lâĂ©vĂ©nement de signal et abandonne la requĂȘte.
Lorsquâune extraction est abandonnĂ©e, sa promesse est rejetĂ©e avec une erreur AbortError, nous devons donc la gĂ©rer, par ex. dans try..catch.
Voici lâexemple complet avec fetch abandonnĂ© aprĂšs 1 seconde :
// abandonner en 1 seconde
let controller = new AbortController();
setTimeout(() => controller.abort(), 1000);
try {
let response = await fetch('/article/fetch-abort/demo/hang', {
signal: controller.signal
});
} catch(err) {
if (err.name == 'AbortError') { // gĂšre abort()
alert("Aborted!");
} else {
throw err;
}
}
AbortController est évolutif
AbortController est Ă©volutif, il permet dâannuler plusieurs rĂ©cupĂ©rations Ă la fois.
Voici une esquisse de code qui récupÚre de nombreuses urls en parallÚle et utilise un seul contrÎleur pour toutes les abandonner:
let urls = [...]; // une liste d'urls à récupérer en parallÚle
let controller = new AbortController();
// an array of fetch promises
let fetchJobs = urls.map(url => fetch(url, {
signal: controller.signal
}));
let results = await Promise.all(fetchJobs);
// si controller.abort() est appelée d'ailleurs,
// elle interrompt tous les fetches
Si nous avons nos propres tĂąches asynchrones, diffĂ©rentes de fetch, nous pouvons utiliser un seul AbortController pour les arrĂȘter, avec des fetches.
Nous avons juste besoin dâĂ©couter son Ă©vĂ©nement abort dans nos tĂąches :
let urls = [...];
let controller = new AbortController();
let ourJob = new Promise((resolve, reject) => { // notre tĂąche
...
controller.signal.addEventListener('abort', reject);
});
let fetchJobs = urls.map(url => fetch(url, { // fetches
signal: controller.signal
}));
// Wait for fetches and our task in parallel
let results = await Promise.all([...fetchJobs, ourJob]);
// si controller.abort() est appelée d'ailleurs,
// elle interrompt tous les fetches et ourJob
Résumé
AbortControllerest un objet simple qui gĂ©nĂšre un Ă©vĂ©nementabortsur sa propriĂ©tĂ©signallorsque la mĂ©thodeabort()est appelĂ©e (et dĂ©finit Ă©galementsignal.abortedsurtrue).fetchsâintĂšgre avec lui : nous passons la propriĂ©tĂ©signalcomme option, puisfetchlâĂ©coute, il devient donc possible dâannuler lefetch.- Nous pouvons utiliser
AbortControllerdans notre code. Lâinteraction âappelerabort()â â âĂ©couter lâĂ©vĂ©nementabortâ est simple et universelle. Nous pouvons lâutiliser mĂȘme sansfetch.
Commentaires
<code>, pour plusieurs lignes â enveloppez-les avec la balise<pre>, pour plus de 10 lignes - utilisez une sandbox (plnkr, jsbin, codepenâŠ)