Start · Sprachen · JavaScript · Referenz · FetchEvent.preloadResponse

FetchEvent.preloadResponse

Eigenschaft

Schreibgeschützte Eigenschaft, die ein <code>Promise</code> liefert. Es wird mit der per Navigation Preload geladenen <code>Response</code> erfüllt oder mit <code>undefined</code>, falls kein Preload lief.

seit JavaScript Baseline 2022: Chrome 59+, Edge 18+, Firefox 99+, Kategorie: webapi

Signatur

FetchEvent.preloadResponse

Beschreibung

FetchEvent.preloadResponse ist eine schreibgeschützte Eigenschaft des FetchEvent im Service Worker. Sie liefert ein Promise, das mit der Response des Navigation Preload erfüllt wird. Wenn für die Anfrage kein Preload gestartet wurde, wird das Promise mit undefined erfüllt. Das passiert zum Beispiel, wenn Navigation Preload ausgeschaltet ist, wenn es sich nicht um eine Navigationsanfrage handelt oder wenn der Browser die Funktion nicht unterstützt.

Ohne Navigation Preload wartet der Browser bei einer Seitennavigation erst, bis der Service Worker gestartet ist. Erst danach kann der Worker den Netzwerk-Request absetzen. Ist Navigation Preload über registration.navigationPreload.enable() eingeschaltet, startet der Browser den Request für die Navigation parallel zum Hochfahren des Service Workers. Im fetch-Handler greift man dann über event.preloadResponse auf diese bereits laufende Antwort zu und verhindert so einen doppelten Request.

Typischerweise wird Navigation Preload im activate-Event eingeschaltet. Im fetch-Handler gilt dann: Zuerst den Cache prüfen, dann die Preload-Antwort nutzen und erst zuletzt auf fetch(event.request) zurückfallen. Preload-Anfragen senden standardmäßig den Header Service-Worker-Navigation-Preload: true. Den Wert kann man mit navigationPreload.setHeaderValue() ändern, damit der Server zum Beispiel nur einen Teil der Seite ausliefert.

Rückgabewert

Typ
Promise<Response | undefined>
Beschreibung
Ein Promise, das mit der Response des Navigation Preload erfüllt wird. Wurde kein Preload ausgelöst, wird es mit undefined erfüllt.

Beispiele

Navigation Preload im activate-Event einschalten

// sw.js
self.addEventListener('activate', (event) => {
  event.waitUntil((async () => {
    // Nur einschalten, wenn der Browser die Funktion unterstützt
    if (self.registration.navigationPreload) {
      await self.registration.navigationPreload.enable();
      const state = await self.registration.navigationPreload.getState();
      console.log('Navigation Preload aktiv:', state.enabled);
    }
  })());
});
Navigation Preload aktiv: true

Reihenfolge im fetch-Handler: Cache, dann Preload, dann Netzwerk

// sw.js
self.addEventListener('fetch', (event) => {
  if (event.request.mode !== 'navigate') return;

  event.respondWith((async () => {
    // 1. Cache prüfen
    const cached = await caches.match(event.request);
    if (cached) return cached;

    // 2. Preload-Antwort verwenden, falls vorhanden
    const preloaded = await event.preloadResponse;
    if (preloaded) return preloaded;

    // 3. Auf normalen Netzwerk-Request zurückfallen
    return fetch(event.request);
  })());
});

Preload-Antwort mit Offline-Rückfallseite und Cache-Aktualisierung

// sw.js
const CACHE = 'seiten-v1';

self.addEventListener('fetch', (event) => {
  if (event.request.mode !== 'navigate') return;

  event.respondWith((async () => {
    try {
      const response = (await event.preloadResponse) ?? (await fetch(event.request));
      // Kopie im Hintergrund in den Cache legen
      const cache = await caches.open(CACHE);
      event.waitUntil(cache.put(event.request, response.clone()));
      return response;
    } catch (err) {
      // Offline: Rückfallseite aus dem Cache liefern
      return (await caches.match('/offline.html')) ?? Response.error();
    }
  })());
});

Header-Wert für Preload-Anfragen setzen

// sw.js – der Server kann anhand des Headers z. B. nur den Seiteninhalt liefern
self.addEventListener('activate', (event) => {
  event.waitUntil((async () => {
    if (!self.registration.navigationPreload) return;
    await self.registration.navigationPreload.enable();
    await self.registration.navigationPreload.setHeaderValue('content-only');
  })());
});

// Wichtig · Fallstricke

  • Immer auf undefined prüfen: Das Promise liefert undefined, wenn Navigation Preload ausgeschaltet ist, die Anfrage keine Navigation ist oder der Browser die Funktion nicht unterstützt. Deshalb sollte man immer fetch(event.request) als Rückfall vorsehen.
  • Preload-Antwort nicht ungenutzt lassen: Ist Preload eingeschaltet, aber die Antwort wird nicht verwendet (zum Beispiel weil sie aus dem Cache kommt), gibt Chrome eine Warnung aus: „The service worker navigation preload request was cancelled before 'preloadResponse' settled“. Abhilfe: Das Promise mit event.waitUntil(event.preloadResponse) an das Event binden. Wer Seiten meist aus dem Cache ausliefert, sollte Navigation Preload besser ganz ausschalten, weil sonst unnötiger Netzwerkverkehr entsteht.
  • Nur einmal verwendbar: Der Body der zurückgegebenen Response kann nur einmal gelesen werden. Wer die Antwort cachen und ausliefern will, muss sie mit response.clone() kopieren.
  • Caching am Server: Wenn der Server je nach Header Service-Worker-Navigation-Preload unterschiedliche Inhalte ausliefert, muss er Vary: Service-Worker-Navigation-Preload setzen. Sonst liefern HTTP-Caches womöglich die falsche Variante aus.
  • Kompatibilität: Unterstützt in Chromium-Browsern ab Version 59, in Firefox ab 99 und in Safari ab 15.4. Vor dem Einschalten per Feature-Erkennung prüfen: if (self.registration.navigationPreload). Nur in sicheren Kontexten (HTTPS) verfügbar, da Service Worker HTTPS voraussetzen.