Signatur
Beschreibung
Mit Client.postMessage() kommuniziert ein Service Worker aktiv mit den Seiten, die er kontrolliert bzw. die zu seinem Scope gehören. Das Client-Objekt bekommt man typischerweise über self.clients.get(id), self.clients.matchAll() oder über event.source in einem message-Event des Service Workers.
Auf der Seite des Clients wird die Nachricht als MessageEvent auf navigator.serviceWorker ausgelöst – nicht auf window. Man registriert den Empfänger also mit navigator.serviceWorker.addEventListener("message", …) oder über navigator.serviceWorker.onmessage. Die Daten stehen in event.data, der sendende Service Worker in event.source.
Die Nachricht wird mit dem Structured-Clone-Algorithmus kopiert. Damit lassen sich Objekte, Arrays, Map, Set, Date, Blob, ArrayBuffer usw. übertragen – aber keine Funktionen, DOM-Knoten oder Klasseninstanzen mit Prototyp. Übertragbare Objekte wie ArrayBuffer oder MessagePort können über den transfer-Parameter ohne Kopie weitergereicht werden.
Typische Einsatzfälle: Benachrichtigung über ein verfügbares Update, Rückmeldung zum Stand einer Hintergrundsynchronisation, Weiterleiten von Push-Daten an offene Tabs oder Antworten auf Anfragen, die eine Seite zuvor per ServiceWorker.postMessage() gestellt hat.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $message Pflicht | any | Die zu sendenden Daten. Müssen per Structured Clone kopierbar sein, sonst wird eine DataCloneError-DOMException geworfen. |
|
| $transfer | Array<Transferable> | [] | Optionale Liste übertragbarer Objekte (z. B. ArrayBuffer, MessagePort), deren Besitz an den Client übergeht. Im Service Worker sind sie danach unbrauchbar. |
| $options | { transfer?: Array<Transferable> } | {} | Alternative Form: Objekt mit der Eigenschaft transfer, die dieselbe Bedeutung wie der Array-Parameter hat. |
Beispiele
Allen offenen Tabs eine Nachricht schicken
// sw.js – nach Aktivierung alle Fenster informieren
self.addEventListener("activate", (event) => {
event.waitUntil((async () => {
await self.clients.claim();
const allClients = await self.clients.matchAll({ type: "window", includeUncontrolled: true });
for (const client of allClients) {
client.postMessage({ type: "SW_AKTIVIERT", version: "2.1.0" });
}
})());
});
// main.js – Empfang auf der Seite
navigator.serviceWorker.addEventListener("message", (event) => {
if (event.data?.type === "SW_AKTIVIERT") {
console.log(`Neue Version aktiv: ${event.data.version}`);
}
});
Auf eine Anfrage der Seite antworten (event.source)
// main.js – Seite fragt den Cache-Status ab
const registration = await navigator.serviceWorker.ready;
navigator.serviceWorker.onmessage = (event) => {
if (event.data.type === "CACHE_STATUS") {
console.log("Einträge im Cache:", event.data.count);
}
};
registration.active.postMessage({ type: "GET_CACHE_STATUS" });
// sw.js – antwortet genau dem anfragenden Client
self.addEventListener("message", (event) => {
if (event.data.type !== "GET_CACHE_STATUS") return;
event.waitUntil((async () => {
const cache = await caches.open("static-v1");
const keys = await cache.keys();
event.source.postMessage({ type: "CACHE_STATUS", count: keys.length });
})());
});
Gezielt an den auslösenden Client einer Fetch-Anfrage senden
// sw.js
self.addEventListener("fetch", (event) => {
if (!event.request.url.includes("/api/")) return;
event.respondWith((async () => {
try {
return await fetch(event.request);
} catch {
const client = await self.clients.get(event.clientId);
client?.postMessage({ type: "OFFLINE", url: event.request.url });
return new Response(JSON.stringify({ offline: true }), {
headers: { "Content-Type": "application/json" }
});
}
})());
});
ArrayBuffer ohne Kopie übertragen
// sw.js – große Binärdaten an einen Client übergeben
const sendeDaten = async (clientId) => {
const client = await self.clients.get(clientId);
const buffer = new ArrayBuffer(1024 * 1024); // 1 MiB
client.postMessage({ type: "BINAER", buffer }, [buffer]);
console.log(buffer.byteLength); // Buffer wurde übertragen
};
// Wichtig · Fallstricke
- Empfänger ist
navigator.serviceWorker, nichtwindow: Einwindow.addEventListener("message", …)bekommt diese Nachrichten nicht. - Zwischenspeicherung beim Laden: Nachrichten werden erst zugestellt, wenn die Seite ihre Nachrichtenwarteschlange startet. Das passiert automatisch beim Setzen von
navigator.serviceWorker.onmessage, nachDOMContentLoadedoder durch explizitesnavigator.serviceWorker.startMessages(). BeiaddEventListenerfrüh im Ladevorgang ggf.startMessages()aufrufen. - Nicht klonbare Daten (Funktionen, DOM-Knoten, Symbole) lösen eine
DataCloneErroraus. Klasseninstanzen verlieren ihren Prototyp. - Service Worker kann beendet werden: Asynchrone Arbeit vor dem Senden immer in
event.waitUntil()einbetten, sonst wird der Worker evtl. vor dempostMessage()gestoppt. - Übertragene Objekte werden im Service Worker unbrauchbar (
byteLengthwird 0). - Sicherheit: Clients gehören immer zum selben Ursprung wie der Service Worker, dennoch sollten eingehende Nachrichten per
type-Feld validiert und nie ungeprüft ininnerHTMLgeschrieben werden. - Kompatibilität: In allen modernen Browsern verfügbar; Service Worker erfordern HTTPS (Ausnahme:
localhost). Die Options-Objekt-Variante ist neuer als die Array-Variante.