Es ist üblich, dass Webseiten Daten (oder „Beacons“) an ihren Server zurücksenden müssen. Denken Sie beispielsweise an Analysedaten für die aktuelle Sitzung eines Nutzers. Für Entwickler ist das ein Balanceakt: ständige, möglicherweise redundante Anfragen reduzieren, ohne das Risiko einzugehen, dass Daten verloren gehen, wenn der Tab geschlossen wurde oder der Nutzer wegnavigiert, bevor ein Beacon gesendet werden kann.
Bisher haben Entwickler pagehide
- und visibilitychange
-Ereignisse verwendet, um die Seite beim Entladen zu erfassen, und dann navigator.sendBeacon()
oder ein fetch()
mit keepalive
, um Beacon-Daten zu senden. Bei beiden Ereignissen gibt es jedoch schwierige Sonderfälle, die sich je nach Browser des Nutzers unterscheiden. Manchmal werden die Ereignisse gar nicht gesendet, insbesondere auf Mobilgeräten.
fetchLater()
ist ein Vorschlag, diese Komplexität durch einen einzigen API-Aufruf zu ersetzen. Sie funktioniert genau wie der Name vermuten lässt: Der Browser wird aufgefordert, dafür zu sorgen, dass eine Anfrage zu einem bestimmten Zeitpunkt in der Zukunft gestellt wird, auch wenn die Seite geschlossen oder der Nutzer zu einer anderen Seite wechselt.
fetchLater()
ist in Chrome ab Version 121 (veröffentlicht im Januar 2024) für Tests mit echten Nutzern im Rahmen eines Ursprungstests verfügbar. Dieser läuft bis zum 3. September 2024.
Mit der fetchLater()
API
const fetchLaterResult = fetchLater(request, options);
fetchLater()
nimmt zwei Argumente an, die in der Regel mit denen von fetch()
identisch sind:
- Die
request
, entweder eine String-URL oder eineRequest
-Instanz. - Ein optionales
options
-Objekt, das dieoptions
vonfetch()
mit einem Zeitlimit namensactivateAfter
verlängert.
fetchLater()
gibt ein FetchLaterResult
zurück, das derzeit nur eine einzige schreibgeschützte Property activated
enthält. Diese wird auf true
gesetzt, wenn „später“ verstrichen ist und die Abfrage erfolgt ist. Alle Antworten auf die fetchLater()
-Anfrage werden verworfen.
request
Die einfachste Verwendung ist eine URL allein:
fetchLater('/endpoint/');
Aber genau wie bei fetch()
können auch für eine fetchLater()
-Anfrage eine große Anzahl von Optionen festgelegt werden, einschließlich benutzerdefinierter Header, Anmeldedatenverhalten, POST
-Textkörper und AbortController
signal
, um sie gegebenenfalls abzubrechen.
fetchLater('/endpoint/', {
method: 'GET',
cache: 'no-store',
mode: 'same-origin',
headers: {Authorization: 'SUPER_SECRET'},
});
options
Das Optionsobjekt erweitert die Optionen von fetch()
um ein Zeitlimit, activateAfter
, falls die Anfrage nach Ablauf des Zeitlimits oder beim Entladen der Seite ausgelöst werden soll, je nachdem, was zuerst eintritt.
So können Sie entscheiden, ob Sie Daten so spät wie möglich oder zu einem späteren Zeitpunkt erhalten möchten.
Wenn Nutzer Ihre App beispielsweise normalerweise den ganzen Arbeitstag lang geöffnet lassen, sollten Sie eine Zeitüberschreitung von einer Stunde festlegen, um detailliertere Analysen zu erhalten und gleichzeitig dafür zu sorgen, dass ein Beacon gesendet wird, wenn der Nutzer die App vor Ablauf dieser Stunde schließt. Für die nächste Stunde kann dann eine neue fetchLater()
eingerichtet werden.
const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});
Anwendungsbeispiel
Ein Problem bei der Messung der Core Web Vitals im Feld besteht darin, dass sich die Leistungsmesswerte ändern können, bis der Nutzer eine Seite tatsächlich verlässt. So können beispielsweise jederzeit größere Layout-Shifts auftreten oder die Seite reagiert noch länger auf eine Interaktion.
Sie sollten jedoch nicht riskieren, alle Leistungsdaten aufgrund von fehlerhaften oder unvollständigen Beacons beim Auslagern der Seite zu verlieren. Sie ist der perfekte Kandidat für fetchLater()
.
In diesem Beispiel wird die web-vitals.js-Bibliothek verwendet, um die Messwerte zu überwachen, und fetchLater()
, um die Ergebnisse an einen Analyseendpunkt zu senden:
import {onCLS, onINP, onLCP} from 'web-vitals';
const queue = new Set();
let fetchLaterController;
let fetchLaterResult;
function updateQueue(metricUpdate) {
// If there was an already complete request for whatever
// reason, clear out the queue of already-sent updates.
if (fetchLaterResult?.activated) {
queue.clear();
}
queue.add(metricUpdate);
// JSON.stringify used here for simplicity and will likely include
// more data than you need. Replace with a preferred serialization.
const body = JSON.stringify([...queue]);
// Abort any existing `fetchLater()` and schedule a new one with
// the update included.
fetchLaterController?.abort();
fetchLaterController = new AbortController();
fetchLaterResult = fetchLater('/analytics', {
method: 'POST',
body,
signal: fetchLaterController.signal,
activateAfter: 60 * 60 * 1000, // Timeout to ensure timeliness.
});
}
onCLS(updateQueue);
onINP(updateQueue);
onLCP(updateQueue);
Jedes Mal, wenn ein Messwert aktualisiert wird, wird ein vorhandener geplanter fetchLater()
mit einer AbortController
abgebrochen und ein neuer fetchLater()
mit dem Update erstellt.
fetchLater()
jetzt verwenden
Wie bereits erwähnt, ist fetchLater()
bis Chrome 126 in einem Ursprungstest verfügbar. Einstieg in Herkunftstests
Für lokale Tests kann fetchLater
mit dem Flag „Experimentelle Webplattformfunktionen“ unter chrome://flags/#enable-experimental-web-platform-features
aktiviert werden. Sie können die Funktion auch aktivieren, indem Sie Chrome über die Befehlszeile mit --enable-experimental-web-platform-features
oder dem gezielteren Flag --enable-features=FetchLaterAPI
ausführen.
Wenn du die Funktion auf einer öffentlichen Seite verwendest, solltest du die Funktion erkennen lassen, indem du prüfst, ob die globale fetchLater
definiert ist, bevor du sie verwendest:
if (globalThis.fetchLater) {
// Set up beaconing using fetchLater().
// ...
}
Feedback
Das Feedback von Entwicklern ist entscheidend, um neue Web-APIs zu optimieren. Melden Sie Probleme und geben Sie Feedback auf GitHub.