Signatur
Beschreibung
Die schreibgeschützte Eigenschaft source der Schnittstelle ExtendableMessageEvent verweist auf das Objekt, das die Nachricht an den Service Worker geschickt hat. Meist ist das ein Client bzw. WindowClient, also ein Tab, ein Fenster oder ein Worker, der navigator.serviceWorker.controller.postMessage() oder registration.active.postMessage() aufgerufen hat.
Wofür braucht man das? Mit source kann der Service Worker gezielt dem Absender antworten, ohne alle Clients über clients.matchAll() durchsuchen zu müssen. Außerdem lassen sich über source.id, source.url und source.type Absender unterscheiden, etwa um Nachrichten aus fremden Pfaden abzulehnen.
Der Typ ist laut Spezifikation Client | ServiceWorker | MessagePort | null. Kommt die Nachricht von einem anderen Service Worker, ist source ein ServiceWorker-Objekt. Wurde das Ereignis synthetisch mit new ExtendableMessageEvent() erzeugt und dabei keine Quelle angegeben, ist der Wert null.
Rückgabewert
WindowClient mit id, url, type und postMessage(). Gibt es keine Quelle, ist der Wert null.Beispiele
Dem Absender direkt antworten (Service Worker)
// sw.js
self.addEventListener('message', (event) => {
const client = event.source;
if (!client) return;
if (event.data?.type === 'PING') {
client.postMessage({ type: 'PONG', clientId: client.id });
}
});
// main.js (Seite)
navigator.serviceWorker.addEventListener('message', (e) => {
console.log('Antwort vom SW:', e.data.type);
});
const reg = await navigator.serviceWorker.ready;
reg.active.postMessage({ type: 'PING' });
Absender prüfen und asynchrone Arbeit mit waitUntil absichern
// sw.js
self.addEventListener('message', (event) => {
const src = event.source;
// Nur Fenster-Clients aus dem eigenen Ursprung akzeptieren
if (!(src instanceof WindowClient)) return;
const url = new URL(src.url);
if (url.origin !== self.location.origin) return;
if (event.data?.type === 'CACHE_URLS') {
event.waitUntil((async () => {
const cache = await caches.open('v1');
await cache.addAll(event.data.urls);
src.postMessage({ type: 'CACHED', count: event.data.urls.length });
})());
}
});
Absender-Typ unterscheiden
// sw.js
self.addEventListener('message', (event) => {
const { source } = event;
if (source === null) {
console.log('Keine Quelle (synthetisches Event)');
} else if (source instanceof Client) {
console.log(`Client (${source.type}):`, source.url);
} else if (source instanceof ServiceWorker) {
console.log('Anderer Service Worker:', source.scriptURL);
} else if (source instanceof MessagePort) {
console.log('Nachricht über MessagePort');
}
});
// Wichtig · Fallstricke
- Nur im Service-Worker-Kontext:
ExtendableMessageEventkommt ausschließlich beimmessage-Ereignis imServiceWorkerGlobalScopevor. Auf der Seite selbst empfängt man ein normalesMessageEvent, dessensourcedort einServiceWorkerist. - Auf
nullprüfen: Vor dem Aufruf vonsource.postMessage()sollte man prüfen, obsourcegesetzt ist, sonst gibt es einenTypeError. - Lebensdauer: Der Service Worker kann nach dem Ereignis beendet werden. Asynchrone Antworten (Cache,
fetch) gehören deshalb inevent.waitUntil(). - Sicherheit: Nachrichten kommen zwar nur von Clients desselben Ursprungs, trotzdem sollte man
event.datavalidieren und bei Bedarfsource.urlprüfen. Ungeprüfte Daten gehören nicht in Cache-Schlüssel oder URLs. - Kompatibilität: Wird in Chrome, Edge, Firefox und Safari (ab 11.1) unterstützt. Service Worker brauchen HTTPS oder
localhost. Firefox stellt Service Worker in privaten Fenstern teilweise nicht bereit.