à noto che fetch ritorna una prime. JavaScript comunemente non ha però il concetto di âinterruzioneâ di una promise. Come possiamo fare quindi ad interrompere una chiamata fetch?
Câè uno speciale operatore built-in per questo scopo: AbortController, il quale può essere usato per interrompere fetch ed anche altri tasks asincroni.
Lâutilizzo è molto semplice:
- Step 1: Creare un controller:
Create a controller:
let controller = new AbortController();
Un controller è un oggetto estremamente semplice.
- Possiede un solo metodo
abort(), - Ed unâunica proprietÃ
signalche permette di impostare dei controllori di evento (event listeneres).
Quando viene invocato il metodo abort():
controller.signalemette lâevento"abort".- la proprietÃ
controller.signal.aborteddiventatrue.
Generalmente il processo si suddivide in due parti:
- quella che esegue lâoperazione annullabile, imposta il listener su
controller.signal. - quella che annulla: essa chiama
controller.abort()quando necessario.
Qui vediamo un esempio completo (ancora senza fetch):
let controller = new AbortController();
let signal = controller.signal;
// La parte che esegue un'operazione annullabile
// ottiene l'oggetto "signal"
// ed imposta il controllore di eventi di attivarsi quando viene invocato controller.abort()
signal.addEventListener('abort', () => alert("abort!"));
// L'altra parte, che cancella (in un qualsiasi punto più avanti):
controller.abort(); // abort!
// L'evento si innesca e il segnale di aborted diventa true
alert(signal.aborted); // true
Potremmo implementare lo stesso tipo controllo di eventi nel nostro codice, anche senza lâoggetto AbortController.
Ma ciò che dà valore è che fetch è ottimizzato per lavorare con lâoggetto AbortController, poiché è integrato.
let controller = new AbortController();
fetch(url, {
signal: controller.signal
});
Il metodo fetch è in grado di lavorare con AbortController. Starà in attesa dellâevent abort su signal.
Ora, per abortire la richiesta, invochiamo controller.abort():
controller.abort();
Abbiamo finito: fetch riceve lâevent da signal ed interrompe la richiesta.
Quando un fetch viene interrotto, la promise viene rifiutata con un errore AbortError, quindi dovremmo prevedere una sua gestione, e.g. allâinterno di un try..catch.
Qui vediamo lâesempio completo con fetch, che viene interrotto dopo 1 secondo:
// interrompi in 1 secondo
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') { // gestisci l'abort()
alert("Aborted!");
} else {
throw err;
}
}
AbortController è scalabile
AbortController è scalabile e può cancellare fetches multipli in una volta.
Ad esempio, qui valutiamo molti url in parallelo e il controller li interrompe tutti:
let urls = [...]; // un elenco di urls di cui fare il fetch in parallelo
let controller = new AbortController();
// un array di fetch promises
let fetchJobs = urls.map(url => fetch(url, {
signal: controller.signal
}));
let results = await Promise.all(fetchJobs);
// se controller.abort() è chiamato da qualche parte del codice
// saranno interrotte tutte le fetches
Se abbiamo dei jobs asincroni, oltre a fetch, possiamo usare un singoloAbortController per fermarli insieme alle fetches.
Dobbiamo solo ascoltare il suo evento abort:
let urls = [...];
let controller = new AbortController();
let ourJob = new Promise((resolve, reject) => { // un nostro task
...
controller.signal.addEventListener('abort', reject);
});
let fetchJobs = urls.map(url => fetch(url, { // fetches
signal: controller.signal
}));
// Attende per le and ed il nostro task in parallelo
let results = await Promise.all([...fetchJobs, ourJob]);
// se controller.abort() è chiamato da qualche parte del codice
// saranno interrotte tutte le fetches e ourJob
Riepilogo
AbortControllerè un semplice oggetto che genera eventi diabortsulla proprietÃsignalquando viene invocato il metodoabort()(ed imposta anchesignal.abortedatrue).fetchsi integra con esso: se passiamo la proprietÃsignalcome opzione,fetchè in grado di controllarla, quindi sarà possibile interrompere lâoperazione difetch.- Possiamo utilizzare
AbortControllernel nostro codice. La chiamataabort()" â âascolterà lâeventoabortâ. Possiamo utilizzarla anche senzafetch.
Commenti
<code>, per molte righe â includile nel tag<pre>, per più di 10 righe â utilizza una sandbox (plnkr, jsbin, codepenâ¦)