Frontem
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!

Udostępnij na Facebooku, Twitterze lub LinkedIn