Signatur
Beschreibung
Ein MessageChannel besteht aus zwei miteinander verbundenen MessagePort-Objekten: port1 und port2. Was an einem Port mit postMessage() gesendet wird, kommt am anderen Port als message-Ereignis an. port2 liefert den zweiten dieser beiden Ports.
Üblicherweise bleibt port1 im aktuellen Kontext. port2 wird als übertragbares Objekt (Transferable) an einen anderen Kontext geschickt, etwa ein <iframe>, einen Web Worker oder einen Service Worker. Dazu übergibt man es im Transfer-Array von postMessage(). So entsteht ein privater, direkter Kommunikationskanal zwischen zwei Kontexten, unabhängig vom globalen message-Kanal von window.
Die Eigenschaft ist schreibgeschützt und gibt bei jedem Zugriff dasselbe MessagePort-Objekt zurück. Nach der Übertragung an einen anderen Kontext ist der Port im Ursprungskontext neutralisiert: Er lässt sich dort nicht mehr sinnvoll verwenden.
Rückgabewert
port1 verbunden und wird typischerweise an einen anderen Kontext übertragen.Beispiele
Port an ein iframe übertragen
const channel = new MessageChannel();
const iframe = document.querySelector('iframe');
// Antworten aus dem iframe über port1 empfangen
channel.port1.onmessage = (event) => {
console.log('Antwort aus iframe:', event.data);
};
iframe.addEventListener('load', () => {
// port2 im Transfer-Array übergeben – nicht nur als Daten!
iframe.contentWindow.postMessage('init', 'https://widget.example.com', [channel.port2]);
});
// Im iframe (widget.example.com):
// window.addEventListener('message', (event) => {
// if (event.origin !== 'https://parent.example.com') return;
// const [port] = event.ports;
// port.postMessage('Hallo vom Widget');
// });
Anfrage/Antwort mit einem Web Worker
// main.js
const worker = new Worker('worker.js');
const askWorker = (payload) => new Promise((resolve) => {
const { port1, port2 } = new MessageChannel();
port1.onmessage = (event) => {
resolve(event.data);
port1.close();
};
worker.postMessage(payload, [port2]);
});
const result = await askWorker({ a: 2, b: 3 });
console.log('Summe:', result);
// worker.js
// self.onmessage = ({ data, ports }) => {
// ports[0].postMessage(data.a + data.b);
// };
Beide Ports lokal verbinden (z. B. für Tests)
const { port1, port2 } = new MessageChannel();
port2.addEventListener('message', (event) => {
console.log('port2 empfängt:', event.data);
});
// Bei addEventListener muss start() explizit aufgerufen werden
port2.start();
port1.postMessage({ typ: 'ping' });
console.log(port2 instanceof MessagePort);
// Wichtig · Fallstricke
- Nur per Transfer-Liste übertragen: Legt man
port2nur in die Nachrichtendaten statt ins Transfer-Array (drittes Argument vonwindow.postMessage()bzw. zweites vonWorker.postMessage()), wird einDataCloneErrorausgelöst. - Neutralisierung: Nach der Übertragung ist
port2im Ursprungskontext unbrauchbar. Dort gesendete Nachrichten gehen verloren. start()nicht vergessen: WeraddEventListener('message', …)stattonmessagenutzt, mussport.start()aufrufen. Sonst kommen keine Nachrichten an.- Sicherheit: Beim Übertragen an ein iframe immer einen konkreten
targetOriginangeben, nicht'*'. Sonst kann ein fremdes Dokument den Port abgreifen. Auf der Empfängerseiteevent.originprüfen, bevor manevent.portsverwendet. - Speicher: Nicht mehr benötigte Ports mit
close()schließen, damit keine Ressourcen offen bleiben. - Kompatibilität: Wird von allen modernen Browsern unterstützt. In Node.js ist
MessageChannelab Version 15 global verfügbar, davor überrequire('worker_threads').