Ulepszanie odrzucania strony w synchronicznej funkcji XMLHttpRequest()

Zmniejszanie opóźnień nawigacji

Jan Kowalski
Joe Medley

Często w momencie zamknięcia strony lub aplikacji pojawiają się nieprzesłane statystyki albo inne dane. Aby zapobiec utracie danych, niektóre witryny używają synchronicznego wywołania XMLHttpRequest(), aby strona lub aplikacja pozostała otwarta, dopóki dane nie zostaną przekazane na serwer. Istnieją nie tylko lepsze sposoby zapisywania danych, ale także ta metoda zwiększa wygodę użytkowników, opóźniając zamknięcie strony o kilka sekund.

Należy to zmienić, a przeglądarki działają zgodnie z oczekiwaniami. Specyfikacja XMLHttpRequest() zostanie już wycofana i usunięta. W pierwszej kolejności Chrome 80 nie zezwala na wywołania synchroniczne wewnątrz kilku modułów obsługi zdarzeń, w szczególności beforeunload, unload, pagehide i visibilitychange, gdy są one uruchamiane przy zamykaniu. W komponencie WebKit niedawno zostało również zatwierdzono wprowadzenie tej samej zmiany w działaniu.

W tym artykule przedstawię krótko opcje dla tych, którzy potrzebują czasu na zaktualizowanie witryny, i przedstawię alternatywy dla XMLHttpRequest().

Tymczasowe rezygnacje

Chrome nie chce po prostu pobierać wtyczki na XMLHttpRequest(), dlatego dostępnych jest kilka tymczasowych opcji rezygnacji. W przypadku stron w internecie dostępny jest okres próbny origin. Dzięki temu dodajesz do nagłówków stron token dotyczący źródła, który umożliwia synchroniczne wywołania funkcji XMLHttpRequest(). Ta opcja przestanie być dostępna na krótko przed udostępnieniem Chrome 89, gdzieś w marcu 2021 r. Klienci korzystający z Chrome Enterprise mogą też używać flagi zasady AllowSyncXHRInPageDismissal, która kończy się równocześnie.

Inne rozwiązania

Niezależnie od sposobu wysyłania danych z powrotem na serwer, najlepiej unikać oczekiwania do momentu wyładowania strony, aby przesłać wszystkie dane naraz. Nie tylko negatywnie wpływa na wygodę użytkowników, ale też nie działa w nowoczesnych przeglądarkach na niezawodny i niezawodny interfejs, a w przypadku problemów może wiązać się z ryzykiem utraty danych. W szczególności zdarzenia wyładowania często nie uruchamiają się w przeglądarkach mobilnych, ponieważ istnieje wiele sposobów zamknięcia karty lub przeglądarki w mobilnych systemach operacyjnych bez wywoływania zdarzenia unload. W XMLHttpRequest() używany był mały ładunek. Teraz jest to wymóg. W obu przypadkach obowiązuje limit przesyłania wynoszący 64 KB na kontekst, zgodnie ze specyfikacją.

Pobieranie utrzymywania aktywności

Interfejs Fetch API zapewnia niezawodne metody obsługi interakcji z serwerem i spójny interfejs do stosowania w interfejsach API różnych platform. Wśród dostępnych opcji jest keepalive, który zapewnia, że żądanie jest kontynuowane niezależnie od tego, czy strona, która go otworzyła, pozostaje otwarta:

window.addEventListener('unload', {
  fetch('/siteAnalytics', {
    method: 'POST',
    body: getStatistics(),
    keepalive: true
  });
}

Metoda fetch() ma tę zaletę, że ma większą kontrolę nad tym, co jest wysyłane do serwera. Nie widzę w tym przykładzie tego, że fetch() zwraca też obietnicę, która kończy się z obiektem Response. Chcę uniknąć wyładowywania strony z pamięci, więc wolę nic z tym nie robić.

SendBeacon()

SendBeacon() używa wbudowanego interfejsu Fetch API, dlatego ma taki sam limit ładunku, który wynosi 64 KB. Zapewnia też kontynuowanie żądania po wyładowaniu strony. Jego główną zaletą jest prostota. Umożliwia przesyłanie danych w jednym wierszu kodu:

window.addEventListener('unload', {
  navigator.sendBeacon('/siteAnalytics', getStatistics());
}

Podsumowanie

Zwiększona dostępność fetch() w różnych przeglądarkach może spowodować, że w pewnym momencie zostanie ona usunięta z platformy XMLHttpRequest(). Dostawcy przeglądarek zgadzają się, że powinna zostać usunięta, ale to zajmie trochę czasu. Wycofanie jednego z najgorszych przypadków użycia to pierwszy krok, który poprawia wrażenia wszystkich użytkowników.

Fot. Matthew Hamilton na stronie Unsplash