Signatur
Beschreibung
postMessage() verschickt eine Nachricht über einen BroadcastChannel. Empfänger sind alle anderen Instanzen mit demselben Kanalnamen im selben Ursprung (Origin). Das können andere Tabs, Fenster, iframes, Web Worker oder Service Worker sein. Die sendende Instanz bekommt ihre eigene Nachricht nicht. Eine zweite Instanz mit demselben Namen im selben Kontext empfängt sie dagegen schon.
Die Nachricht wird mit dem Structured-Clone-Algorithmus kopiert. Damit lassen sich neben einfachen Werten auch Objekte, Arrays, Map, Set, Date, Blob, ArrayBuffer und ähnliche Typen senden. Funktionen, DOM-Knoten und Objekte mit Symbol-Schlüsseln lassen sich nicht kopieren. Anders als bei Window.postMessage() gibt es keine Übertragung (Transfer-Liste). Die Daten werden also immer kopiert.
Typische Einsatzfälle sind die Synchronisierung zwischen Tabs: Logout in allen Fenstern, Aktualisieren eines Warenkorbs, Verteilen von Theme-Änderungen oder das Signal, dass ein Service Worker neue Inhalte zwischengespeichert hat. Die Zustellung ist asynchron. Empfänger reagieren über das Ereignis message und lesen die Daten aus event.data.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $message Pflicht | any (structured-cloneable) | Die zu sendenden Daten. Erlaubt ist jeder Wert, den der Structured-Clone-Algorithmus kopieren kann, z. B. Objekte, Arrays, Date, Map, Blob oder ArrayBuffer. |
Rückgabewert
undefined). Ob und wann die Nachricht ankommt, wird nicht bestätigt.Beispiele
Einfache Nachricht zwischen Tabs senden
// In beiden Tabs ausführen
const channel = new BroadcastChannel('app-events');
channel.addEventListener('message', (event) => {
console.log('Empfangen:', event.data);
});
// In einem Tab:
channel.postMessage({ type: 'greeting', text: 'Hallo aus Tab A' });
Logout in allen Tabs synchronisieren
const authChannel = new BroadcastChannel('auth');
const logout = async () => {
await fetch('/api/logout', { method: 'POST' });
authChannel.postMessage({ type: 'logout', at: Date.now() });
location.href = '/login';
};
authChannel.onmessage = ({ data }) => {
if (data.type === 'logout') {
console.log('Abgemeldet in anderem Tab um', new Date(data.at).toLocaleTimeString());
location.href = '/login';
}
};
document.querySelector('#logout-btn')?.addEventListener('click', logout);
Service Worker meldet Cache-Update an alle Seiten
// sw.js
const updates = new BroadcastChannel('sw-updates');
self.addEventListener('activate', (event) => {
event.waitUntil((async () => {
await caches.open('v2');
updates.postMessage({ type: 'cache-updated', version: 'v2' });
})());
});
// main.js
const updatesClient = new BroadcastChannel('sw-updates');
updatesClient.onmessage = ({ data }) => {
if (data.type === 'cache-updated') {
console.log(`Neue Version ${data.version} verfügbar – bitte neu laden.`);
}
};
Fehler bei nicht klonbaren Daten abfangen
const channel = new BroadcastChannel('demo');
try {
channel.postMessage({ callback: () => {} });
} catch (err) {
console.log(err.name);
}
channel.close();
try {
channel.postMessage('nach close');
} catch (err) {
console.log(err.name);
}
// Wichtig · Fallstricke
- Kein Echo: Die sendende Instanz empfängt ihre eigene Nachricht nicht. Andere Instanzen mit demselben Namen im selben Kontext empfangen sie aber.
- Ausnahmen: Nicht klonbare Daten wie Funktionen oder DOM-Knoten lösen
DataCloneErroraus. Ein Aufruf nachclose()löstInvalidStateErroraus. - Deserialisierungsfehler: Kann ein Empfänger die Daten nicht rekonstruieren, wird dort
messageerrorstattmessageausgelöst. - Nur gleicher Ursprung: Für Kommunikation über Ursprünge hinweg ist
Window.postMessage()nötig. Dort sollte man immertargetOriginundevent.originprüfen. Browser mit Storage-Partitionierung (z. B. Safari, Firefox, Chrome) trennen Kanäle zusätzlich nach Top-Level-Site. Ein eingebettetes iframe erreicht dann nicht unbedingt denselben Ursprung als eigenständigen Tab. - Sicherheit: Jeder Code im selben Ursprung kann mitlesen und Nachrichten einschleusen. Übertragen Sie daher keine Geheimnisse wie Tokens ungeschützt und prüfen Sie eingehende Daten, bevor Sie sie z. B. per
innerHTMLins DOM schreiben (XSS). - Keine Transfer-Liste: Große
ArrayBufferwerden immer kopiert. Das kann Speicher und Zeit kosten. - Keine Zustellgarantie: Nachrichten werden nicht gepuffert. Tabs, die später geöffnet werden, erhalten frühere Nachrichten nicht. Dauerhafter Zustand gehört zusätzlich in
localStorageoder IndexedDB. - Kanäle, die nicht mehr gebraucht werden, mit
close()schließen, damit sie vom Garbage Collector freigegeben werden können.