Start · Sprachen · JavaScript · Referenz · FetchEvent.resultingClientId

FetchEvent.resultingClientId

Eigenschaft

Schreibgeschützter String mit der <code>id</code> des Clients, der durch eine Navigation entsteht und den bisherigen Client ersetzt. Bei Anfragen ohne Navigation ist der Wert ein leerer String.

seit JavaScript Chrome/Edge 72+, Firefox 65+, Safari 16.4+ (nur im Kategorie: webapi

Signatur

FetchEvent.resultingClientId

Beschreibung

resultingClientId ist eine schreibgeschützte Eigenschaft des FetchEvent-Interfaces. Sie ist nur im fetch-Handler eines Service Workers verfügbar. Bei einer Navigationsanfrage, also wenn ein Tab, ein Fenster oder ein <iframe> ein neues Dokument lädt, enthält sie die ID des Clients, der für das neue Dokument angelegt wird. Der Wert steht schon fest, bevor das Dokument überhaupt existiert.

Damit schließt die Eigenschaft eine Lücke: Bei Navigationen ist event.clientId leer, weil die anfragende Seite noch nicht existiert. Über resultingClientId kann der Service Worker die Anfrage trotzdem einem Client zuordnen und ihm später etwas schicken, zum Beispiel über postMessage(). Die Eigenschaft eignet sich auch für Protokollierung, Statistik oder um Zustände pro Seite zu verwalten.

Bei Unterressourcen wie Bildern, Skripten, CSS oder fetch()-Aufrufen einer Seite ist resultingClientId ein leerer String. Dort gibt event.clientId an, welcher Client die Anfrage gestellt hat. Auch bei Anfragen mit dem Ziel "report" bleibt der Wert leer.

Mit clients.get(event.resultingClientId) bekommst du das zugehörige Client-Objekt. Dieser Client entsteht aber erst, wenn die Antwort ausgeliefert und das Dokument geladen wird. Deshalb gehört das Warten auf den Client in event.waitUntil() und nicht in event.respondWith().

Rückgabewert

Typ
string
Beschreibung
Die ID des Clients, der durch die Navigation entsteht. Bei Anfragen ohne Navigation ist es ein leerer String "".

Beispiele

Navigationen und Unterressourcen unterscheiden

// sw.js
self.addEventListener('fetch', (event) => {
  if (event.request.mode === 'navigate') {
    console.log('Navigation, neuer Client:', event.resultingClientId);
    console.log('clientId (leer):', JSON.stringify(event.clientId));
  } else {
    console.log('Unterressource von Client:', event.clientId);
    console.log('resultingClientId (leer):', JSON.stringify(event.resultingClientId));
  }
});
Navigation, neuer Client: 7b1c0e2a-4f3d-4a8e-9c61-2d5e8f0a1b33 clientId (leer): "" Unterressource von Client: 7b1c0e2a-4f3d-4a8e-9c61-2d5e8f0a1b33 resultingClientId (leer): ""

Neu geladener Seite nach der Navigation eine Nachricht schicken

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

  // Antwort sofort liefern, nicht auf den Client warten
  event.respondWith(fetch(event.request));

  // Auf den neuen Client in waitUntil warten
  event.waitUntil((async () => {
    const id = event.resultingClientId;
    if (!id) return;
    const client = await self.clients.get(id);
    client?.postMessage({ type: 'sw-hallo', url: event.request.url });
  })());
});

// main.js (Seite)
navigator.serviceWorker.addEventListener('message', (e) => {
  if (e.data.type === 'sw-hallo') {
    console.log('Service Worker grüßt für', e.data.url);
  }
});
Service Worker grüßt für https://example.com/produkte

Seitenaufrufe pro Client protokollieren

// sw.js
const seitenaufrufe = new Map();

self.addEventListener('fetch', (event) => {
  const { request, resultingClientId } = event;
  if (request.mode === 'navigate' && resultingClientId) {
    seitenaufrufe.set(resultingClientId, {
      url: request.url,
      zeit: Date.now()
    });
    console.log(`Clients mit Navigation: ${seitenaufrufe.size}`);
  }
});
Clients mit Navigation: 1

// Wichtig · Fallstricke

  • Keine Blockade in respondWith(): Warte nie innerhalb der Promise von respondWith() auf clients.get(event.resultingClientId). Der Client entsteht erst, wenn die Antwort da ist. Warten auf ihn kann deshalb hängen bleiben oder undefined liefern. Verwende stattdessen event.waitUntil().
  • Leerer String statt null: Ohne Navigation ist der Wert "". Prüfe ihn mit einer Wahrheitsprüfung (if (id)) und nicht mit !== null.
  • Nicht verwechseln: clientId ist der anfragende Client (bei Navigationen leer). resultingClientId ist der Client, der durch die Navigation entsteht. Das ältere replacesClientId steht in der Spezifikation, kaum ein Browser unterstützt es.
  • Kompatibilität: Chromium-Browser unterstützen die Eigenschaft seit Version 72, Firefox seit Version 65, Safari erst in neueren Versionen. Sie gibt es nur im Service-Worker-Kontext und nur über HTTPS oder localhost. In älteren Browsern ist sie undefined.
  • Die ID ist ein zufälliger, undurchsichtiger String. Werte ihn nicht aus und speichere ihn nicht dauerhaft, denn er gilt nur, solange der Client existiert.