Przerywanie zapytań do API z AbortController
Pisząc aplikacje internetowe, czasami potrzebujemy przerwać zapytanie asynchroniczne, które jest w trakcie wykonywania. Powodów jest wiele — danie możliwości użytkownikowi anulowania przesyłania pliku, przerwanie istniejącego zapytania ponieważ zmienił się stan aplikacji czy przed odmontowaniem komponentu Reactowego, żeby zapobiec wyciekowi pamięci. Dzięki AbortController, które rozszerza fetch API jesteśmy w stanie to zrobić w parę chwil, a sama wiedza na temat tej techniki skutecznie rozszerzy twoją wiedzę.
Geneza i wparcie
AbortController został zaimplementowany po tym jak na GitHubie w ramach Issue zrodziła się potrzeba dodania takiej funkcjonalności. Samo API jest już dojrzałe i z bardzo szerokim wsparciem na wszystkich istotnych przeglądarkach (zgodnie z caniuse wsparcie na poziomie 94%), lecz gdy będzie potrzeba wykorzystania go na starszych przeglądarkach to z pomocą wychodzi nam polyfill.
AbortController w praktyce
AbortController nie jest mocno rozbudowaną klasą. Udostępnia nam metodę abort(), oraz właściwość signal, która jest obiektem typu AbortSignal. signal dodatkowo zawiera w sobie właściwość-flagę aborted, która jest true gdy zapytanie zostanie przez nas przerwane.
Przyjrzyjmy się prostej implementacji:
const controller = new AbortController()
console.log(controller.signal.aborted) // => false
fetch(firstUrl, {
signal: controller.signal,
})
fetch(secondUrl, {
signal: controller.signal,
})
controller.abort()
console.log(controller.signal.aborted) // => true
Jak widać, nie jest to specjalnie skomplikowane. Najpierw musimy stworzyć nową instancję AbortController, następnie przekazujemy signal do jednego lub wielu fetch, a na koniec w zależności od potrzeb wykonujemy abort() w celu anulowania zapytania.
Obsługa wyjątków
Jest jeszcze jedna rzecz, którą należy wiedzieć. Wywołując abort() rzucany jest wyjątek, który należy obsłużyć. Błąd jest typu DOMException, a zidentyfikować można go po nazwie AbortError.
DOMException: The operation was aborted. {
message: "The operation was aborted. "
name: "AbortError",
...
}
Spójrzmy na przykładową obsługę wyjątku:
fetch(url, { signal })
.then(...)
.catch((error) => {
if (error.name === 'AbortError') {
console.error('Request was aborted');
}
})