Signatur
Beschreibung
fetchLater() legt eine HTTP-Anfrage an, die der Browser nicht sofort sendet. Er hält sie zurück und sendet sie in einem von zwei Fällen: wenn das Dokument zerstört wird (Tab schließen, wegnavigieren, Entfernen aus dem Back/Forward-Cache) oder wenn die in activateAfter angegebene Zeit abgelaufen ist. Die Anfrage geht also auch dann raus, wenn die Seite abrupt beendet wird. Sie hängt nicht von unzuverlässigen Ereignissen wie unload oder beforeunload ab.
Die Methode eignet sich vor allem für Analyse- und Telemetriedaten, Sitzungsende-Meldungen und das Zusammenfassen von Messwerten (Beaconing). Wichtig: Eine zurückgehaltene Anfrage lässt sich nicht ändern. Um Daten zu aktualisieren, bricht man die alte Anfrage über ein AbortSignal ab und ruft fetchLater() mit dem neuen Stand noch einmal auf. So wird am Ende nur der aktuelle Stand gesendet.
Die Signatur entspricht weitgehend fetch(). Es gibt aber einen Unterschied: Der Rückgabewert ist kein Promise<Response>, sondern ein FetchLaterResult-Objekt. Dessen Eigenschaft activated zeigt, ob die Anfrage schon gesendet wurde. Auf die Antwort des Servers hat man keinen Zugriff.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $resource Pflicht | string | URL | Request | Ziel-URL oder ein Request-Objekt. Die URL muss vertrauenswürdig sein, also https: nutzen (oder localhost). Sonst wird ein TypeError geworfen. |
|
| $options | object | {} | Dieselben Optionen wie bei fetch() (method, headers, body, signal, credentials …), dazu die Option activateAfter. |
| $options.activateAfter | number | Zeit in Millisekunden, nach der die Anfrage spätestens gesendet wird, auch wenn das Dokument noch existiert. Ein negativer Wert führt zu einem RangeError. Ohne Angabe wird erst beim Entladen gesendet. |
|
| $options.signal | AbortSignal | Bricht die zurückgehaltene Anfrage ab, solange sie noch nicht gesendet wurde. So ersetzt man sie durch eine aktuellere. | |
| $options.body | string | Blob | FormData | URLSearchParams | ArrayBuffer | Inhalt der Anfrage. ReadableStream ist nicht erlaubt, weil die Größe vorab bekannt sein muss (sonst TypeError). |
Rückgabewert
activated (boolean). Sie ist true, sobald der Browser die Anfrage gesendet hat.Beispiele
Sitzungsende melden, wenn die Seite verlassen wird
// Wird gesendet, sobald der Nutzer den Tab schließt oder wegnavigiert
const result = fetchLater('/api/session-end', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionId: 'abc123', endedAt: Date.now() })
});
console.log(result.activated);
Analysedaten sammeln und die zurückgehaltene Anfrage laufend ersetzen
const events = [];
let controller = null;
const track = (name) => {
events.push({ name, t: Date.now() });
// Alte, noch nicht gesendete Anfrage abbrechen
controller?.abort();
controller = new AbortController();
fetchLater('/api/analytics', {
method: 'POST',
body: JSON.stringify(events),
signal: controller.signal,
activateAfter: 60_000 // spätestens nach einer Minute senden
});
};
track('page_view');
track('button_click');
// Gesendet wird nur die letzte Anfrage mit beiden Ereignissen
Browser-Unterstützung prüfen und auf sendBeacon ausweichen
const reportOnExit = (url, data) => {
const body = JSON.stringify(data);
if ('fetchLater' in window) {
try {
return fetchLater(url, { method: 'POST', body });
} catch (err) {
// z. B. QuotaExceededError bei überschrittenem Kontingent
console.warn('fetchLater fehlgeschlagen:', err.name);
}
}
// Ausweichlösung: beim Verstecken der Seite per sendBeacon senden
addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
navigator.sendBeacon(url, body);
}
}, { once: true });
};
reportOnExit('/api/metrics', { lcp: 1840, cls: 0.02 });
Status prüfen mit activated
const result = fetchLater('/api/ping', { activateAfter: 2000 });
setTimeout(() => {
console.log('Gesendet:', result.activated);
}, 3000);
// Wichtig · Fallstricke
- Kompatibilität: Die Methode ist experimentell und bisher nur in Chromium-Browsern verfügbar (ab Chrome 135). Firefox und Safari unterstützen sie nicht. Prüfen Sie daher immer mit
'fetchLater' in windowund sehen Sienavigator.sendBeacon()oderfetch(..., { keepalive: true })als Ausweichlösung vor. - Nur in sicheren Kontexten (HTTPS). Die Ziel-URL muss ebenfalls vertrauenswürdig sein.
- Kontingent: Die Größe aller zurückgehaltenen Anfragen ist begrenzt: etwa 64 KiB pro Ursprung und 640 KiB pro Dokument der obersten Ebene. Wird die Grenze überschritten, wirft die Methode sofort einen
QuotaExceededError. Deshalb gehört der Aufruf in einentry...catch-Block. - In iframes wird die Methode über die Berechtigungsrichtlinien
deferred-fetchunddeferred-fetch-minimalgesteuert. Fremde iframes erhalten standardmäßig nur ein kleines Kontingent. - Auf die Antwort des Servers gibt es keinen Zugriff, weder ihren Inhalt noch ihren Status. Die Methode ist also nur für „Abschicken und vergessen“-Szenarien gedacht.
- Ein
ReadableStreamalsbodyist nicht erlaubt. Ein negativer Wert füractivateAfterlöst einenRangeErroraus. - Wird die Seite in den Back/Forward-Cache verschoben, kann der Browser die Anfrage früher senden. So gehen keine Daten verloren, falls die Seite nie zurückkehrt.