Signatur
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 alsmessage-Event aufnavigator.serviceWorkeran.
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
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);
}
});
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');
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 imServiceWorkerGlobalScope. Auf der Seite selbst heißt das Gegenstücknavigator.serviceWorkerbzw.ServiceWorker. - Kein Konstruktor:
new Client()wirft einenTypeError. - Fenster sind WindowClients:
focus()undnavigate()gibt es nur beitype === "window".focus()klappt nur innerhalb einer Nutzerinteraktion, etwa innotificationclick. - 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
clientvor der Nutzung aufundefinedprü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:
frameTypeundtypewerden weitgehend unterstützt, die experimentelle EigenschaftlifecycleStatedagegen nur in Chromium.