Start · Sprachen · JavaScript · Referenz · ServiceWorkerContainer: message

ServiceWorkerContainer: message

Ereignis

Wird auf dem <code>ServiceWorkerContainer</code> einer Seite ausgelöst, wenn ein Service Worker per <code>client.postMessage()</code> eine Nachricht an diese Seite schickt.

seit JavaScript Baseline: alle modernen Browser (seit ca. 2018); n Kategorie: webapi

Signatur

navigator.serviceWorker.addEventListener("message", (event) => { … })

Beschreibung

Über das message-Ereignis des ServiceWorkerContainer (erreichbar über navigator.serviceWorker) empfängt eine Seite Nachrichten, die ein Service Worker mit Client.postMessage() an sie schickt. So kann der Worker zum Beispiel melden, dass ein Cache-Update fertig ist, dass eine neue Version bereitsteht oder dass Push-Daten angekommen sind.

Du kannst den Listener mit navigator.serviceWorker.addEventListener("message", handler) registrieren oder über die Eigenschaft navigator.serviceWorker.onmessage setzen. Der Handler bekommt ein MessageEvent. Die wichtigsten Eigenschaften:

  • event.data: die übertragenen Daten. Sie werden mit dem Structured-Clone-Algorithmus kopiert, deshalb funktionieren auch Map, Blob, ArrayBuffer usw.
  • event.source: das ServiceWorker-Objekt, das die Nachricht gesendet hat. Darüber kannst du direkt antworten.
  • event.origin: der Ursprung (Origin) des Absenders.
  • event.ports: mitgeschickte MessagePort-Objekte.

Wichtig ist die Nachrichten-Warteschlange des Clients. Nachrichten vom Service Worker werden zuerst zurückgehalten und erst zugestellt, wenn die Warteschlange aktiviert ist. Das passiert automatisch, sobald das Dokument fertig geparst ist (DOMContentLoaded), sobald onmessage gesetzt wird oder wenn du navigator.serviceWorker.startMessages() aufrufst. Ein Listener, der nur mit addEventListener registriert wurde, bekommt also vor dem Ende des Parsens noch keine Nachrichten. Dafür gehen auch keine frühen Nachrichten verloren.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignistyp, hier immer "message".
$listener Pflicht (event: MessageEvent) => void | EventListenerObject Die Rückruffunktion, die für jede eingehende Nachricht aufgerufen wird. Sie erhält ein MessageEvent mit data, source, origin und ports.
$options boolean | AddEventListenerOptions false Optionen wie once, signal (zum Entfernen über einen AbortController) oder capture.

Rückgabewert

Typ
void
Beschreibung
addEventListener() hat keinen Rückgabewert. Der Handler selbst bekommt ein MessageEvent.

Beispiele

Service Worker schickt eine Nachricht an alle Tabs, die Seite empfängt sie

// sw.js: an alle kontrollierten Fenster senden
self.addEventListener("activate", (event) => {
  event.waitUntil((async () => {
    const clients = await self.clients.matchAll({ type: "window" });
    for (const client of clients) {
      client.postMessage({ type: "SW_ACTIVATED", version: "2.1.0" });
    }
  })());
});

// main.js: auf der Seite empfangen
navigator.serviceWorker.addEventListener("message", (event) => {
  const { type, version } = event.data;
  if (type === "SW_ACTIVATED") {
    console.log(`Neuer Service Worker aktiv: ${version}`);
  }
});
Neuer Service Worker aktiv: 2.1.0

Mit onmessage empfangen und über event.source antworten

// main.js: onmessage aktiviert die Warteschlange sofort
navigator.serviceWorker.onmessage = (event) => {
  if (event.data?.type === "PING") {
    console.log("Ping vom Service Worker erhalten");
    // event.source ist das ServiceWorker-Objekt des Absenders
    event.source?.postMessage({ type: "PONG", time: Date.now() });
  }
};

// sw.js
self.addEventListener("message", (event) => {
  if (event.data?.type === "PONG") {
    console.log("Antwort vom Client:", event.data.time);
  }
});
Ping vom Service Worker erhalten

Frühe Nachrichten mit startMessages() empfangen und Listener wieder entfernen

const onUpdate = (event) => {
  if (event.data?.type === "CACHE_UPDATED") {
    console.log("Aktualisiert:", event.data.url);
    // Nach der ersten Aktualisierung nicht mehr zuhören
    navigator.serviceWorker.removeEventListener("message", onUpdate);
  }
};

navigator.serviceWorker.addEventListener("message", onUpdate);
// Nachrichten schon vor DOMContentLoaded zustellen lassen
navigator.serviceWorker.startMessages();
Aktualisiert: /api/articles

Listener mit AbortController aufräumen (z. B. in einer SPA-Komponente)

const controller = new AbortController();

navigator.serviceWorker.addEventListener(
  "message",
  (event) => {
    console.log("Nachricht:", event.data);
  },
  { signal: controller.signal }
);

// Später, etwa beim Verlassen der Komponente:
controller.abort(); // entfernt den Listener
Nachricht: { type: 'SYNC_DONE' }

// Wichtig · Fallstricke

  • Nachrichten-Warteschlange: Mit addEventListener kommen Nachrichten erst nach DOMContentLoaded an. Wenn du sie früher brauchst, rufe navigator.serviceWorker.startMessages() auf oder setze onmessage. Das Setzen von onmessage ruft startMessages() automatisch auf.
  • Richtung verwechselt: Dieses Ereignis läuft auf der Seite. Nachrichten von der Seite an den Worker kommen im Service Worker als message-Ereignis auf self an (ExtendableMessageEvent). Gesendet werden sie mit navigator.serviceWorker.controller.postMessage() oder registration.active.postMessage().
  • controller kann null sein: Beim ersten Laden und nach einem harten Neuladen (Shift+Reload) wird die Seite nicht kontrolliert. Dann schickt der Worker ihr nur Nachrichten, wenn er sie gezielt anspricht, etwa über clients.matchAll({ includeUncontrolled: true }) oder nach clients.claim().
  • Nicht serialisierbare Daten: Funktionen, DOM-Knoten oder Objekte mit Prototyp-Logik lassen sich nicht übertragen. Schlägt die Deserialisierung fehl, wird statt message das Ereignis messageerror ausgelöst.
  • Sicherheit: Behandle event.data nicht ungeprüft als HTML (z. B. per innerHTML). Prüfe am besten einen type-Schlüssel. Service Worker sind immer gleichen Ursprungs, trotzdem ist eine Prüfung auf ein festes Nachrichtenformat sinnvoll.
  • Verfügbarkeit: navigator.serviceWorker gibt es nur in sicheren Kontexten (HTTPS oder localhost). In manchen privaten Modi, z. B. im privaten Modus von Firefox, ist es undefined. Prüfe das vorher mit if (\"serviceWorker\" in navigator).