Start · Sprachen · JavaScript · Referenz · Client.postMessage()

Client.postMessage()

Methode

Sendet aus einem Service Worker eine Nachricht an einen bestimmten Client (Fenster, Worker oder SharedWorker), der dort als <code>message</code>-Event auf <code>navigator.serviceWorker</code> ankommt.

seit JavaScript Baseline: alle modernen Browser (Service-Worker-Un Kategorie: webapi

Signatur

Client.prototype.postMessage(message, transfer) / Client.prototype.postMessage(message, options)

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}`);
  }
});
Neue Version aktiv: 2.1.0

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 });
  })());
});
Einträge im Cache: 12

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, nicht window: Ein window.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, nach DOMContentLoaded oder durch explizites navigator.serviceWorker.startMessages(). Bei addEventListener früh im Ladevorgang ggf. startMessages() aufrufen.
  • Nicht klonbare Daten (Funktionen, DOM-Knoten, Symbole) lösen eine DataCloneError aus. 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 dem postMessage() gestoppt.
  • Übertragene Objekte werden im Service Worker unbrauchbar (byteLength wird 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 in innerHTML geschrieben 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.