Signatur
Beschreibung
Die Eigenschaft ports eines MessageEvent enthält alle MessagePort-Objekte, die der Absender beim Aufruf von postMessage() im Transfer-Argument mitgeschickt hat. So kann der Empfänger einen eigenen, direkten Kommunikationskanal zum Absender (oder zu einem Dritten) übernehmen.
Typischer Einsatz ist das Muster mit MessageChannel: Eine Seite erzeugt einen Kanal, behält port1 und übergibt port2 per postMessage() an ein iframe, einen Worker oder einen Service Worker. Der Empfänger liest den Port über event.ports[0] aus und nutzt ihn für eine exklusive Zwei-Wege-Kommunikation – etwa für Anfrage-Antwort-Muster, ohne globale message-Listener zu belasten.
Das Array ist eingefroren (Object.isFrozen(event.ports) === true) und bei Nachrichten ohne übertragene Ports leer. Übertragene Ports sind beim Absender danach unbrauchbar (neutralisiert), da ihr Besitz an den Empfänger übergeht.
Rückgabewert
MessagePort-Objekte; leeres Array, wenn keine Ports mitgeschickt wurden.Beispiele
Port an ein iframe übergeben und empfangen
// Elternseite
const iframe = document.querySelector('iframe');
const channel = new MessageChannel();
channel.port1.onmessage = (e) => console.log('Antwort aus iframe:', e.data);
iframe.addEventListener('load', () => {
// port2 wird übertragen (drittes Argument = Transfer-Liste)
iframe.contentWindow.postMessage('init', 'https://child.example', [channel.port2]);
});
// Im iframe (https://child.example)
window.addEventListener('message', (event) => {
if (event.origin !== 'https://parent.example') return;
const [port] = event.ports;
if (!port) return;
port.onmessage = (e) => port.postMessage(`Echo: ${e.data}`);
port.postMessage('Kanal steht');
});
Anfrage-Antwort mit einem Worker über einen eigenen Kanal
// main.js
const worker = new Worker('worker.js');
const ask = (payload) => new Promise((resolve) => {
const { port1, port2 } = new MessageChannel();
port1.onmessage = (e) => {
resolve(e.data);
port1.close();
};
worker.postMessage(payload, [port2]);
});
const result = await ask({ op: 'sum', values: [1, 2, 3] });
console.log(result);
// worker.js
self.onmessage = (event) => {
const { op, values } = event.data;
const [replyPort] = event.ports;
if (op === 'sum') replyPort.postMessage(values.reduce((a, b) => a + b, 0));
};
Eigenschaften des ports-Arrays prüfen
const { port1, port2 } = new MessageChannel();
window.addEventListener('message', (event) => {
console.log(event.ports.length);
console.log(Object.isFrozen(event.ports));
console.log(event.ports[0] instanceof MessagePort);
}, { once: true });
window.postMessage('test', '*', [port2]);
// Wichtig · Fallstricke
- Transfer-Liste nötig: Ports erscheinen nur in
event.ports, wenn sie im Transfer-Argument vonpostMessage()(bzw.{ transfer: [...] }) übergeben werden. Stecken sie nur indata, ohne übertragen zu werden, wirft der Aufruf einenDataCloneError. - Eingefroren: Das Array kann nicht verändert werden;
push()o. Ä. schlägt fehl (im Strict Mode mitTypeError). - Neutralisierung: Nach der Übertragung ist der Port beim Absender nicht mehr verwendbar.
- start() bei addEventListener: Wer auf dem empfangenen Port
addEventListener('message', …)stattonmessagenutzt, mussport.start()aufrufen, sonst kommen keine Nachrichten an. - Sicherheit: Bei Cross-Origin-Nachrichten immer
event.originprüfen, bevor ein empfangener Port genutzt wird – sonst kann eine fremde Seite einen Kanal einschleusen. - Bei
message-Events vonWebSocketoderEventSourceistportsstets leer. - Kompatibilität: in allen modernen Browsern sowie in Web-, Shared- und Service-Workern verfügbar.