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.

Ta praktyka musi się zmienić, a przeglądarki na to reagują. Specyfikacja XMLHttpRequest() jest już zaplanowana do wycofania i usunięcia. Chrome 80 podejmuje pierwszy krok, zakazując wywołań synchronicznych w kilku przetwarzaczach zdarzeń, w szczególności beforeunload, unload, pagehidevisibilitychange, gdy są one wywoływane w ramach odrzucenia. WebKit opublikował też niedawno komit wprowadzający tę samą zmianę zachowania.

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

Tymczasowe wyłączenia

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. Obie te opcje mają limit przesyłania wynoszący 64 KB na kontekst, zgodnie z wymaganiami specyfikacji.

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. Jedną z opcji jest keepalive, która zapewnia, że żądanie jest kontynuowane niezależnie od tego, czy strona, która je wywołała, 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. Ponieważ próbuję pozbyć się sposobu wczytywania strony, nie robiłem 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ą jednego 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