- Published on
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');
}
})
Truskawka na torcie
Nie chciałem pozostawiać was z suchymi przykładami w postaci bloków kodu, więc przygotowałem małe demo, na którym możecie zobaczyć jak AbortController
działa w praktyce. Zapytanie posiada jednosekundowy timeout, ponieważ przechodzi przez serwis deelay.me, więc nie ma potrzebny sztucznego spowolnienia sieci w narzędziach developerskich.
Owocnego kodowania!