Signatur
Beschreibung
postMessage() auf einem ServiceWorker-Objekt schickt beliebige Daten an den zugehörigen Service Worker. Die Daten werden mit dem Structured-Clone-Algorithmus kopiert. Dadurch lassen sich Objekte, Arrays, Map, Set, Date, Blob, ArrayBuffer usw. übertragen, Funktionen und DOM-Knoten dagegen nicht. Im Worker kommt die Nachricht als ExtendableMessageEvent im message-Event von self an.
Typische Anwendungsfälle sind: den Worker zu einem sofortigen Update auffordern (skipWaiting), bestimmte URLs gezielt in den Cache laden, Caches leeren oder Konfigurationswerte wie Tokens und Sprache übergeben. Ein ServiceWorker-Objekt bekommt man meist über navigator.serviceWorker.controller (der Worker, der die aktuelle Seite steuert) oder über registration.active, .waiting und .installing.
Die Methode antwortet nicht selbst, denn sie gibt undefined zurück. Brauchst du eine Antwort, hast du zwei Möglichkeiten: Du überträgst einen MessagePort aus einem MessageChannel, oder der Worker antwortet über event.source.postMessage(). Auf der Seite empfängst du die Antwort dann mit navigator.serviceWorker.addEventListener('message', …).
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $message Pflicht | any | Die zu sendenden Daten. Sie müssen mit dem Structured-Clone-Algorithmus kopierbar sein, sonst wird ein DataCloneError ausgelöst. |
|
| $transfer | Transferable[] | [] | Objekte, deren Besitz an den Worker übergeben wird, statt sie zu kopieren, z. B. MessagePort oder ArrayBuffer. Nach der Übergabe sind sie im Absender nicht mehr nutzbar. |
| $options | { transfer?: Transferable[] } | {} | Andere Schreibweise für den zweiten Parameter: ein Objekt mit der Eigenschaft transfer. |
Rückgabewert
MessagePort oder das message-Event von navigator.serviceWorker.Beispiele
Einfache Nachricht an den steuernden Service Worker
// Seite (main.js)
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage({
type: 'CACHE_URLS',
urls: ['/offline.html', '/styles/app.css']
});
}
// sw.js
self.addEventListener('message', (event) => {
if (event.data?.type === 'CACHE_URLS') {
event.waitUntil(
caches.open('v1').then((cache) => cache.addAll(event.data.urls))
);
}
});
Wartenden Worker sofort aktivieren (Update-Banner)
// Seite
const registration = await navigator.serviceWorker.register('/sw.js');
const activateUpdate = () => {
registration.waiting?.postMessage({ type: 'SKIP_WAITING' });
};
// Seite neu laden, sobald der neue Worker die Kontrolle übernimmt
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload();
});
// sw.js
self.addEventListener('message', (event) => {
if (event.data?.type === 'SKIP_WAITING') {
self.skipWaiting();
}
});
Anfrage mit Antwort über MessageChannel
// Seite: Hilfsfunktion, die ein Promise zurückgibt
const askServiceWorker = (message) => new Promise((resolve, reject) => {
const worker = navigator.serviceWorker.controller;
if (!worker) return reject(new Error('Kein aktiver Service Worker'));
const { port1, port2 } = new MessageChannel();
port1.onmessage = (event) => resolve(event.data);
worker.postMessage(message, [port2]);
});
const info = await askServiceWorker({ type: 'GET_VERSION' });
console.log('SW-Version:', info.version);
// sw.js
const VERSION = '1.4.2';
self.addEventListener('message', (event) => {
if (event.data?.type === 'GET_VERSION') {
event.ports[0].postMessage({ version: VERSION });
}
});
Antwort über event.source statt MessageChannel
// sw.js
self.addEventListener('message', (event) => {
if (event.data?.type === 'PING') {
event.source.postMessage({ type: 'PONG', time: Date.now() });
}
});
// Seite
navigator.serviceWorker.addEventListener('message', (event) => {
if (event.data.type === 'PONG') console.log('Antwort erhalten', event.data.time);
});
navigator.serviceWorker.controller?.postMessage({ type: 'PING' });
// Wichtig · Fallstricke
controllerkannnullsein: Beim ersten Seitenaufruf, bei einem Hard-Reload (Umschalt+F5) und bevorclients.claim()gelaufen ist, wird die Seite von keinem Worker gesteuert. Prüfe das vorher oder warte aufnavigator.serviceWorker.readyund nutze dannregistration.active.- Worker kann schlafen: Der Browser beendet untätige Service Worker. Eine Nachricht weckt ihn zwar auf, aber globale Variablen im Worker gehen dabei verloren. Speichere Zustände deshalb in IndexedDB oder in der Cache API.
- Längere Arbeiten mit
event.waitUntil()absichern, sonst beendet der Browser den Worker womöglich, bevor die Arbeit fertig ist. - Structured Clone: Funktionen, DOM-Knoten und Klasseninstanzen samt Prototyp lassen sich nicht übertragen und lösen einen
DataCloneErroraus bzw. verlieren ihren Prototyp. Übertragene (transferable)ArrayBuffersind danach im Absender leer. - Sicherheit: Service Worker gibt es nur in sicheren Kontexten (HTTPS oder localhost) und nur für denselben Ursprung. Prüfe trotzdem im Worker den Nachrichtentyp und die Daten und vertraue
event.datanicht blind. Das gilt besonders, wenn davon Cache-Löschungen oder Netzwerkanfragen abhängen. Bei Bedarf kannst duevent.originbzw.event.sourceprüfen. - Kompatibilität: Die Methode wird in allen modernen Browsern unterstützt (Chrome, Edge, Firefox, Safari 11.1+). Die Schreibweise mit Options-Objekt (
{ transfer }) ist neuer. Für ältere Browser verwendest du besser das Array als zweiten Parameter.