Wenn Sie Analysedaten, Core Web Vitals und Telemetriedaten zuverlässig erfassen möchten, die den gesamten Besuch eines Nutzers auf einer Webseite abdecken (nicht nur bis zum Seitenaufbau), verwenden Sie die fetchLater() API.
Die fetchLater() API ist die zuverlässigste Methode, um Daten an einen Server zu senden, wenn keine Antwort erforderlich ist und die Lieferzeit nicht dringend ist. Das gilt für Daten wie Nutzeranalysen, Telemetrie, Fehlerverfolgung und Leistungsmesswerte wie Core Web Vitals.
Ältere Techniken wie das Erstellen eines <img>-Pixels in einem unload-Ereignis-Listener sind bekanntermaßen unzuverlässig (insbesondere auf Mobilgeräten) und können die Leistung beeinträchtigen, da Seiten nicht für bfcache infrage kommen.
Implementierung
Anfrage planen: Sobald relevante Daten verfügbar sind, rufen Sie
fetchLater()mit Ihrer Datennutzlast auf. Dadurch werden die Daten in die Warteschlange gestellt, um später gesendet zu werden.Nutzlast nach Bedarf aktualisieren: Wenn der Nutzer mehr Daten generiert oder sich der Status ändert, brechen Sie die zuvor geplante Anfrage ab und rufen Sie
fetchLater()noch einmal mit dem vollständig aktualisierten Snapshot auf.Den Browser den Rest erledigen lassen: Wenn der Nutzer die Seite verlässt oder den Tab schließt, sendet der Browser die Nutzlast aus dem letzten
fetchLater()-Aufruf.
Beispielcode
Mit diesem Code wird die Sitzungsdauer des Besuchs eines Nutzers auf einer Seite gemessen. Dabei wird fetchLater() verwendet, um alle 10 Sekunden einen neuen Beacon mit der aktualisierten Sitzungsdauer in die Warteschlange zu stellen.
const ANALYTICS_ENDPOINT = '/path/to/analytics/endpoint';
const sessionData = {
duration: 0,
id: crypto.randomUUID(),
};
let fetchLaterController = null;
function queueBeacon() {
// Abort any pending beacons before creating a new one.
if (fetchLaterController) {
fetchLaterController.abort();
}
fetchLaterController = new AbortController();
// Update session duration to the current page time.
sessionData.duration = performance.now();
// Schedule a fetch for the data payload to be sent later.
// IMPORTANT: wrap the call in a try/catch to handle quota errors.
try {
fetchLater(ANALYTICS_ENDPOINT, {
method: 'POST',
headers: {'content-type': 'application/json'},
body: JSON.stringify(sessionData),
signal: fetchLaterController.signal,
});
} catch (error) {
// Handle errors as needed.
}
}
// Update the session data and queue a new beacon every 10 seconds.
setInterval(queueBeacon, 10000);
Best Practices
- DO: Verwenden Sie
fetchLater(), um Daten an einen Server zu senden, wenn keine Antwort erforderlich ist und es nicht wichtig ist, dass die Daten sofort gesendet werden. - EMPFOHLEN: Verwenden Sie einen
AbortController, um den ausstehenden Abruf abzubrechen, wenn die Daten möglicherweise aktualisiert werden müssen, bevor der Nutzer die Seite verlässt. - DO minimum the payload size to avoid exceeding the quota (currently roughly 64KB per origin).
- EMPFOHLEN: Schließen Sie Aufrufe von
fetchLater()in einentry/catchein, um Kontingentfehler zu beheben. - DO feature detect the presence of
fetchLater()onglobalThisand implement a fallback strategy for browsers that don't support the API. - Verwenden Sie KEIN
ReadableStream-Objekt für den Anfragetext, da dies zu einem Fehler führt.
Browserunterstützung und Fallback-Strategien
Eine Fallback-Strategie ist erforderlich, wenn fetchLater() Ihr Baseline-Ziel nicht erreicht. Aufgrund der verbesserten Zuverlässigkeit und Leistung dieser API sollte jedoch fetchLater() verwendet werden, wenn der Browser dies unterstützt.
Als Fallback-Strategie wird empfohlen, das unten stehende Polyfill zu verwenden, das intern nicht unterstützte Browser mit fetch() mit keepalive oder navigator.sendBeacon() verarbeitet. Ihr eigener Code MUSS fetchLater() direkt aufrufen. Rufen Sie niemals fetch(), sendBeacon() oder andere Beacon APIs selbst auf.
fetchLater()-Polyfill
Verwenden Sie das folgende minimale fetchLater()-Polyfill, das die API in nicht unterstützten Browsern so genau wie möglich implementiert.
Der einzige nennenswerte Verhaltensunterschied bei diesem Polyfill besteht darin, dass visibilitychange verwendet wird, um zu erkennen, wann der Nutzer die Seite verlässt, anstatt sich auf die native Entladeverarbeitung des Browsers zu verlassen. Dies ist ein internes Implementierungsdetail. Ihr Code muss nicht auf visibilitychange oder andere Seiten-Lifecycle-Events warten. Rufen Sie einfach fetchLater() auf und das Polyfill übernimmt die Bereitstellung.
globalThis.fetchLater ??= function fetchLater(url, init = {}) {
let timeoutHandle;
let activated = false;
function sendNow() {
if (!(init.signal && init.signal.aborted)) {
// Use fetch keepalive if the browser supports it or if custom fetch
// parameters are specified (e.g. custom headers or methods).
// Otherwise fall back to `navigator.sendBeacon()`.
if (
'keepalive' in Request.prototype ||
init.method !== 'POST' ||
init.headers
) {
fetch(url, Object.assign({}, init, {keepalive: true}));
activated = true;
} else {
activated = navigator.sendBeacon(url, init.body);
}
}
destroy();
}
function destroy() {
document.removeEventListener('visibilitychange', sendNow);
clearTimeout(timeoutHandle);
}
if (document.visibilityState === 'hidden') {
// If the beacon was created while the page is already hidden, send data
// ASAP but wait until the next microtask to allow all sync code to run.
queueMicrotask(sendNow);
} else {
document.addEventListener('visibilitychange', sendNow);
if (typeof init.activateAfter === 'number' && init.activateAfter >= 0) {
timeoutHandle = setTimeout(sendNow, init.activateAfter);
}
}
if (init.signal) {
init.signal.addEventListener('abort', destroy);
}
return {
get activated() {
return activated;
},
};
};