Ulepszanie zamykania stron w synchronicznych żądaniach XMLHttpRequest

Joe Medley
Joe Medley

Często zdarza się, że w momencie zamknięcia strony lub aplikacji znajdują się na niej nieprzesłane dane z Analytics lub inne dane. Aby zapobiec utracie danych, niektóre witryny używają synchronicznego wywołania XMLHttpRequest(), aby strona lub aplikacja pozostała otwarta do momentu przesłania danych na serwer. Istnieją lepsze sposoby zapisywania danych, a ta metoda pogarsza wygodę użytkowników, ponieważ opóźnia zamknięcie strony nawet o kilka sekund.

Ta praktyka musi się zmienić, a przeglądarki reagują na to. Specyfikacja XMLHttpRequest() jest już przeznaczona do wycofania i usunięcia. Chrome 80 to pierwszy krok w tym kierunku. Przeglądarka ta nie zezwala na synchroniczne wywołania w kilku modułach obsługi zdarzeń, w tym beforeunload, unload, pagehide, i visibilitychange, gdy są one wywoływane w momencie odrzucenia. WebKit również niedawno wprowadził zmianę, która implementuje to samo zachowanie.

Krótko opiszę opcje dla tych, którzy potrzebują czasu na zaktualizowanie swoich witryn, i przedstawię alternatywy dla XMLHttpRequest().

Tymczasowe wyłączenie

Chrome chce dać deweloperom czas na usunięcie zależności od XMLHttpRequest(), dlatego oferujemy tymczasowe opcje rezygnacji.

Dołącz do testu origin trial. W tym celu dodaj do nagłówków strony token specyficzny dla origin, który umożliwi synchroniczne wywołania XMLHttpRequest(). Ta opcja przestanie działać na krótko przed wydaniem Chrome 89, czyli w marcu 2021 r. Klienci Chrome Enterprise mogą też używać flagi zasady AllowSyncXHRInPageDismissal, która przestanie działać w tym samym czasie.

Alternatywy

Niezależnie od tego, jak wysyłasz dane z powrotem na serwer, najlepiej unikać czekania na zamknięcie strony, aby wysłać wszystkie dane naraz. Oprócz pogorszenia komfortu użytkowników zamknięcie strony jest zawodne w nowoczesnych przeglądarkach i może spowodować utratę danych, jeśli coś pójdzie nie tak. W szczególności zdarzenia zamknięcia strony często nie są wywoływane w przeglądarkach mobilnych ponieważ w mobilnych systemach operacyjnych 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 alternatywy mają limit przesyłania 64 KB na kontekst, zgodnie ze specyfikacją.

Utrzymywanie aktywności pobierania

Interfejs Fetch API zapewnia niezawodny sposób obsługi interakcji z serwerem i spójny interfejs do użycia w różnych interfejsach API platformy. Jedną z jego opcji jest keepalive, która zapewnia, że żądanie będzie kontynuowane niezależnie od tego, czy strona, która je wysłała, pozostanie 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 na serwer. W przykładzie nie pokazuję, że fetch() zwraca też obietnicę, która jest rozwiązywana za pomocą obiektu Response. Ponieważ staram się nie przeszkadzać w zamykaniu strony, nie robię z nią nic.

SendBeacon()

SendBeacon() używa pod spodem Fetch API, dlatego ma ten sam limit ładunku 64 KB i zapewnia, że żądanie będzie kontynuowane po zamknięciu strony. Jego główną zaletą jest prostota. Umożliwia przesyłanie danych za pomocą jednego wiersza kodu:

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

Podsumowanie

Dzięki coraz większej dostępności w przeglądarkach fetch(), XMLHttpRequest() zostanie prawdopodobnie usunięte z platformy internetowej. Producenci przeglądarek zgadzają się, że należy go usunąć, ale zajmie to trochę czasu. Wycofanie jednego z najgorszych przypadków użycia to pierwszy krok, który poprawia komfort użytkowników.