Start · Sprachen · JavaScript · Referenz · Client

Client

Schnittstelle

Das <code>Client</code>-Interface steht im Service Worker für einen ausführbaren Kontext wie ein Fenster, einen <code>Worker</code> oder einen <code>SharedWorker</code>, der vom Service Worker kontrolliert wird.

seit JavaScript Baseline: alle modernen Browser (seit 2018), nur i Kategorie: webapi

Signatur

interface Client

Beschreibung

Ein Client-Objekt ist die Sicht eines Service Workers auf einen Kontext, den er steuert oder steuern könnte: einen Dedicated Worker, einen SharedWorker oder ein Dokument (Tab, Fenster, iframe). Fenster-Clients werden durch die spezialisierte Unterklasse WindowClient dargestellt. Sie bietet zusätzlich focus(), navigate(), focused und visibilityState.

Einen Client erzeugt man nie selbst, denn das Interface hat keinen Konstruktor. Man bekommt ihn über die Clients-API des Service Workers (self.clients.matchAll(), self.clients.get(id), self.clients.openWindow()) oder als event.source in einem message-Event. Beim FetchEvent stehen dafür clientId und resultingClientId bereit.

Wichtige Bestandteile:

  • Client.id: eindeutige, stabile Kennung (string) des Clients.
  • Client.type: "window", "worker" oder "sharedworker".
  • Client.url: URL des Clients.
  • Client.frameType: "auxiliary", "top-level", "nested" oder "none".
  • Client.postMessage(message, transfer): schickt eine Nachricht an den Client. Dort kommt sie als message-Event auf navigator.serviceWorker an.

Typische Anwendungsfälle: alle offenen Tabs über ein neues Update informieren, eine Nachricht an genau den Tab zurückschicken, von dem eine Anfrage kam, oder bei einem Klick auf eine Push-Benachrichtigung einen passenden Tab finden und in den Vordergrund holen.

Parameter

Name Typ Default Beschreibung
$message Pflicht any Parameter von Client.postMessage(): der zu sendende Wert. Er wird mit dem Structured-Clone-Algorithmus kopiert. Funktionen und DOM-Knoten sind nicht erlaubt.
$transfer Transferable[] | { transfer: Transferable[] } [] Optional für postMessage(): Objekte wie ArrayBuffer oder MessagePort, deren Besitz an den Client übergeht, statt dass sie kopiert werden. Alternativ als Options-Objekt mit dem Schlüssel transfer.

Rückgabewert

Typ
void
Beschreibung
Client.postMessage() gibt undefined zurück. Die Eigenschaften id, type, url und frameType liefern jeweils einen string.

Beispiele

Alle Clients über ein Update informieren

// service-worker.js
self.addEventListener('activate', (event) => {
  event.waitUntil((async () => {
    await self.clients.claim();
    const allClients = await self.clients.matchAll({
      type: 'all',
      includeUncontrolled: true
    });
    for (const client of allClients) {
      console.log(client.id, client.type, client.url);
      client.postMessage({ type: 'SW_UPDATED', version: '2.1.0' });
    }
  })());
});

// main.js (Seite)
navigator.serviceWorker.addEventListener('message', (event) => {
  if (event.data.type === 'SW_UPDATED') {
    console.log('Neue Version aktiv:', event.data.version);
  }
});
3f2a9c1e-... window https://example.com/ Neue Version aktiv: 2.1.0

Dem sendenden Client antworten (event.source)

// service-worker.js
self.addEventListener('message', (event) => {
  const client = event.source; // Client bzw. WindowClient
  if (event.data === 'PING') {
    client.postMessage({ reply: 'PONG', from: client.id, frame: client.frameType });
  }
});

// main.js
const reg = await navigator.serviceWorker.ready;
navigator.serviceWorker.onmessage = (e) => console.log(e.data);
reg.active.postMessage('PING');
{ reply: 'PONG', from: '3f2a9c1e-...', frame: 'top-level' }

Den Client einer Fetch-Anfrage gezielt ermitteln

// service-worker.js
self.addEventListener('fetch', (event) => {
  if (!event.clientId) return; // z. B. Navigation ohne bestehenden Client
  event.waitUntil((async () => {
    const client = await self.clients.get(event.clientId);
    if (client) {
      client.postMessage({ type: 'FETCH_LOG', url: event.request.url });
    }
  })());
});

Beim Klick auf eine Benachrichtigung einen passenden Tab fokussieren

// service-worker.js
self.addEventListener('notificationclick', (event) => {
  event.notification.close();
  event.waitUntil((async () => {
    const windows = await self.clients.matchAll({ type: 'window' });
    const target = windows.find((c) => new URL(c.url).pathname === '/inbox');
    if (target) {
      await target.focus(); // WindowClient-Methode
    } else {
      await self.clients.openWindow('/inbox');
    }
  })());
});

// Wichtig · Fallstricke

  • Nur im Service Worker: Client-Objekte gibt es ausschließlich im ServiceWorkerGlobalScope. Auf der Seite selbst heißt das Gegenstück navigator.serviceWorker bzw. ServiceWorker.
  • Kein Konstruktor: new Client() wirft einen TypeError.
  • Fenster sind WindowClients: focus() und navigate() gibt es nur bei type === "window". focus() klappt nur innerhalb einer Nutzerinteraktion, etwa in notificationclick.
  • Nicht kontrollierte Clients: clients.matchAll() liefert standardmäßig nur kontrollierte Clients. Mit { includeUncontrolled: true } kommen auch noch nicht übernommene Tabs derselben Origin dazu, zum Beispiel beim ersten Laden.
  • Ohne Wartezeit verloren: Nachrichten an einen Client, der sich gerade schließt oder wegnavigiert, gehen ohne Fehlermeldung verloren. Clients können jederzeit verschwinden, deshalb client vor der Nutzung auf undefined prüfen.
  • Sicherheit: Service Worker laufen nur im sicheren Kontext (HTTPS oder localhost). Sichtbar sind nur Clients derselben Origin. Eingehende Nachrichten sollte man trotzdem validieren und prüfen, bevor man sie weiterverarbeitet.
  • Browser-Unterstützung: frameType und type werden weitgehend unterstützt, die experimentelle Eigenschaft lifecycleState dagegen nur in Chromium.