Verbesserung der Seitenablehnung in synchronen XMLHttpRequest

Joe Medley
Joe Medley

Es ist normal, dass für eine Seite oder App nicht übermittelte Analytics- oder andere Daten vorhanden sind, wenn ein Nutzer sie schließt. Um Datenverlust zu verhindern, verwenden einige Websites einen synchronen Aufruf an XMLHttpRequest(), damit die Seite oder App geöffnet bleibt, bis die Daten an den Server übergeben werden. Es gibt nicht nur bessere Möglichkeiten zum Speichern von Daten, sondern diese Technik führt auch zu einer schlechten Nutzererfahrung, da das Schließen der Seite um bis zu mehrere Sekunden verzögert wird.

Diese Praxis muss sich ändern und Browser reagieren darauf. Die XMLHttpRequest()-Spezifikation wird bereits eingestellt und entfernt. In Chrome 80 wird der erste Schritt unternommen, indem synchrone Aufrufe in mehreren Ereignishandlern nicht mehr zulässig sind, insbesondere in beforeunload, unload, pagehide und visibilitychange, wenn sie beim Schließen ausgelöst werden. In WebKit wurde vor Kurzem ein Commit mit derselben Verhaltensänderung eingefügt.

Ich beschreibe kurz die Optionen für diejenigen, die Zeit benötigen, um ihre Websites zu aktualisieren, und stelle die Alternativen zu XMLHttpRequest() vor.

Vorübergehende Deaktivierungen

Chrome möchte Entwicklern Zeit geben, die Abhängigkeit von XMLHttpRequest() zu entfernen. Daher haben wir vorübergehende Deaktivierungsoptionen angeboten.

An einem Ursprungstest teilnehmen Dadurch fügen Sie Ihren Seitenheadern ein ursprungsspezifisches Token hinzu, das synchrone XMLHttpRequest()-Aufrufe ermöglicht. Diese Option endet kurz vor der Veröffentlichung von Chrome 89, voraussichtlich im März 2021. Chrome-Kunden mit Unternehmensabo können auch das Richtlinien-Flag AllowSyncXHRInPageDismissal verwenden, das zur selben Zeit endet.

Alternativen

Unabhängig davon, wie Sie Daten an den Server zurücksenden, sollten Sie nicht warten, bis die Seite entladen wird, um alle Daten auf einmal zu senden. Die Verwendung von „unload“ führt nicht nur zu einer schlechten Nutzererfahrung, sondern ist in modernen Browsern auch unzuverlässig und birgt das Risiko von Datenverlust, wenn etwas schiefgeht. Insbesondere werden Unload-Ereignisse auf Mobilgeräten häufig nicht ausgelöst, da es auf mobilen Betriebssystemen viele Möglichkeiten gibt, einen Tab oder Browser zu schließen, ohne dass das unload-Ereignis ausgelöst wird. Bei XMLHttpRequest() war die Verwendung kleiner Nutzlasten optional. Jetzt ist es eine Anforderung. Für beide Alternativen gilt ein Uploadlimit von 64 KB pro Kontext, wie in der Spezifikation gefordert.

Fetch-Keepalive

Die Fetch API bietet eine robuste Möglichkeit, Serverinteraktionen zu verarbeiten, und eine einheitliche Schnittstelle für die Verwendung in verschiedenen Plattform-APIs. Eine der Optionen ist keepalive. Damit wird sichergestellt, dass eine Anfrage fortgesetzt wird, unabhängig davon, ob die Seite, auf der sie gestellt wurde, geöffnet bleibt:

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

Die fetch()-Methode bietet den Vorteil, dass Sie mehr Kontrolle darüber haben, was an den Server gesendet wird. Im Beispiel wird nicht gezeigt, dass fetch() auch ein Promise zurückgibt, das mit einem Response-Objekt aufgelöst wird. Da ich das Entladen der Seite nicht behindern möchte, habe ich nichts damit gemacht.

SendBeacon()

SendBeacon() verwendet im Hintergrund die Fetch API. Daher gilt auch hier die Nutzlastbeschränkung von 64 KB und es wird dafür gesorgt, dass eine Anfrage nach dem Entladen einer Seite fortgesetzt wird. Der Hauptvorteil ist die Einfachheit. So können Sie Ihre Daten mit einer einzigen Codezeile senden:

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

Fazit

Da fetch()XMLHttpRequest()� Browseranbieter sind sich einig, dass sie entfernt werden sollte, aber das wird Zeit in Anspruch nehmen. Die Einstellung eines der schlimmsten Anwendungsfälle ist ein erster Schritt, um die Nutzerfreundlichkeit für alle zu verbessern.