Ulepszanie odrzucania strony w synchronicznej funkcji XMLHttpRequest()

Ograniczanie opóźnień w nawigacji

Joe Medley
Joe Medley

Często zdarza się, że w momencie zamknięcia strony lub aplikacji przez użytkownika znajdują się na niej nieprzesłane dane analityczne lub inne dane. Aby zapobiec utracie danych, niektóre witryny używają wywołania synchronicznego XMLHttpRequest(), aby utrzymać stronę lub aplikację otwartą do czasu przekazania danych na serwer. Istnieją lepsze sposoby zapisywania danych, a ta technika powoduje opóźnienie zamykania strony nawet o kilka sekund, co powoduje nieprzyjemne wrażenia użytkownika.

To podejście musi się zmienić, a przeglądarki reagują na nie. Specyfikacja XMLHttpRequest() jest przeznaczona do wycofania i usunięcia. W pierwszej kolejności Chrome 80 blokuje wywołania synchroniczne w kilku modułach obsługi zdarzeń, w szczególności beforeunload, unload, pagehide i visibilitychange, gdy są one uruchamiane w ramach odrzucenia. Niedawno zespół WebKit wprowadził tę samą zmianę działania.

W tym artykule opiszę krótko opcje dla osób, które potrzebują czasu na zaktualizowanie swoich witryn, oraz przedstawię alternatywne rozwiązania dla XMLHttpRequest().

Tymczasowe rezygnacje

Chrome nie chce po prostu odłączyć XMLHttpRequest(), dlatego dostępne są tymczasowe opcje rezygnacji. W przypadku witryn w internecie dostępny jest okres próbny. W ten sposób do nagłówków stron dodasz token dotyczący pochodzenia, który umożliwia asynchroniczne wywołania XMLHttpRequest(). Ta opcja zostanie wycofana w marcu 2021 r., tuż przed wydaniem Chrome 89. Klienci korzystający z Chrome Enterprise mogą też użyć flagi zasad AllowSyncXHRInPageDismissal, która wygasa w tym samym czasie.

Alternatywy

Niezależnie od tego, jak wysyłasz dane z powrotem na serwer, nie warto czekać, aż strona się rozładuje, aby wysłać wszystkie dane naraz. Oprócz tego, że powoduje nieprzyjemne wrażenia użytkownika, unload jest niepewnym rozwiązaniem w przypadku nowoczesnych przeglądarek i może spowodować utratę danych, jeśli coś pójdzie nie tak. W szczególności zdarzenia unload często nie są wywoływane w przeglądarkach mobilnych, ponieważ w systemach operacyjnych urządzeń mobilnych istnieje wiele sposobów na zamknięcie karty lub przeglądarki bez wywołania zdarzenia unload. W przypadku XMLHttpRequest() używanie małych ładunków było opcjonalne. Teraz jest to wymagane. Zgodnie ze specyfikacją obie jego wersje mogą mieć limit przesyłania wynoszący 64 KB na kontekst.

Pobieranie informacji o utrzymywaniu aktywności

Interfejs Fetch API zapewnia niezawodne narzędzie do obsługi interakcji z serwerem oraz spójny interfejs do stosowania w różnych interfejsach API platform. Wśród dostępnych opcji jest keepalive, który zapewnia ciągłość żądania niezależnie od tego, czy strona, na której zostało ono wyświetlone, pozostaje otwarta:

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

Metoda fetch() ma tę zaletę, że zapewnia większą kontrolę nad tym, co jest wysyłane do serwera. W przykładzie nie pokazuję, że funkcja fetch() zwraca również obietnicę, która rozwiązuje się z obiektem Response. Próbuję pozbyć się sposobu wczytywania strony, więc nie robię z tym nic.

SendBeacon()

SendBeacon() w podstawie korzysta z interfejsu Fetch API, dlatego ma to samo ograniczenie ładunku 64 KB i zapewnia, że żądanie jest kontynuowane po usunięciu strony. Jego główną zaletą jest prostota. Umożliwia on przesyłanie danych za pomocą pojedynczego wiersza kodu:

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

Podsumowanie

Dzięki zwiększonej dostępności fetch() w różnych przeglądarkach XMLHttpRequest() zostanie w pewnym momencie prawdopodobnie usunięta z platformy internetowej. Dostawcy przeglądarek zgadzają się, że należy je usunąć, ale zajmie to trochę czasu. Wycofanie jednej z najgorszych opcji użycia to pierwszy krok, który poprawia wrażenia użytkowników.

Zdjęcie: Matthew Hamilton, Unsplash