Jak víme, fetch
vrátí slib. A JavaScript obecně nemá žádný koncept „zrušení“ slibu. Jak tedy můžeme zrušit probíhající fetch
? Např. pokud akce uživatele na našem webu ukazují, že fetch
už není potřeba.
Pro tyto účely existuje speciální vestavěný objekt:AbortController
. Lze jej použít k přerušení nejen fetch
, ale také další asynchronní úlohy.
Použití je velmi jednoduché:
Objekt AbortController
Vytvořte ovladač:
let controller = new AbortController();
Ovladač je extrémně jednoduchý objekt.
- Má jednu metodu
abort()
, - A jedna vlastnost
signal
který na něm umožňuje nastavit posluchače událostí.
Když abort()
se jmenuje:
controller.signal
vysílá"abort"
událost.controller.signal.aborted
vlastnost se změní natrue
.
Obecně máme v procesu dvě strany:
- Ten, který provádí zrušitelnou operaci, nastaví posluchače na
controller.signal
. - Ten, který se ruší:volá
controller.abort()
když je potřeba.
Zde je úplný příklad (bez fetch
ještě):
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!
// The event triggers and signal.aborted becomes true
alert(signal.aborted); // true
Jak vidíme, AbortController
je pouze prostředkem k předání abort
události při abort()
se na to říká.
Stejný druh naslouchání události bychom mohli implementovat do našeho kódu sami, bez AbortController
objekt.
Ale co je cenné, je fetch
ví, jak pracovat s AbortController
objekt. Je v něm integrován.
Použití s načítáním
Aby bylo možné zrušit fetch
, předejte signal
vlastnost AbortController
jako fetch
možnost:
let controller = new AbortController();
fetch(url, {
signal: controller.signal
});
fetch
metoda ví, jak pracovat s AbortController
. Bude poslouchat abort
události na signal
.
Nyní pro zrušení zavolejte controller.abort()
:
controller.abort();
Hotovo:fetch
získá událost z signal
a zruší požadavek.
Když je načítání přerušeno, jeho příslib se odmítne s chybou AbortError
, tak bychom to měli zvládnout, např. v try..catch
.
Zde je úplný příklad s fetch
přerušeno po 1 sekundě:
// abort in 1 second
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') { // handle abort()
alert("Aborted!");
} else {
throw err;
}
}
AbortController je škálovatelný
AbortController
je škálovatelný. Umožňuje zrušit více načtení najednou.
Zde je náčrt kódu, který načítá mnoho urls
paralelně a používá jediný ovladač k jejich zrušení:
let urls = [...]; // a list of urls to fetch in parallel
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);
// if controller.abort() is called from anywhere,
// it aborts all fetches
Pokud máme vlastní asynchronní úlohy, odlišné od fetch
, můžeme použít jeden AbortController
zastavit je společně s aporty.
Musíme jen poslouchat jeho abort
událost v našich úkolech:
let urls = [...];
let controller = new AbortController();
let ourJob = new Promise((resolve, reject) => { // our task
...
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]);
// if controller.abort() is called from anywhere,
// it aborts all fetches and ourJob
Shrnutí
AbortController
je jednoduchý objekt, který generujeabort
událost na jehosignal
vlastnost přiabort()
je volána metoda (a také nastavujesignal.aborted
natrue
).fetch
integruje se s ním:předámesignal
vlastnost jako možnost a potéfetch
naslouchá, takže je možné přerušitfetch
.- Můžeme použít
AbortController
v našem kódu. Volejteabort()
" → "poslouchejteabort
Interakce události“ je jednoduchá a univerzální. Můžeme jej použít i bezfetch
.