MessageChannel

Lesson 3 · ~8 minutes · iframe this time

Transfer a port

Keep port1. Move port2. The original handle dies. The twin lives in the other context.

A MessagePort is transferable, not cloneable. You move it in a transfer list on a window (or worker) postMessage. The payload of that hop can be a dummy string. The port arrives as event.ports[0], a new object in the receiver’s realm, still entangled with the end you kept. (HTML §9.4.1, §9.3.3, MDN: Using channel messaging)

const { port1, port2 } = new MessageChannel();
port1.onmessage = onMsg;
iframe.contentWindow.postMessage("init", origin, [port2]);

// iframe
const port = event.ports[0];
port.onmessage = onMsg;   // start() implied

Transfer is irreversible. The sender’s port2 is detached (neutered): it is not a live twin anymore, and transferring it again throws DataCloneError. Putting the port in the message data instead of the transfer list is the same throw — structured clone has no serializable copy of a port. The received port’s queue is born disabled; onmessage still implies start(). (HTML §2.7.2, §9.4.4 transfer steps)

Feel the handoff

A real MessageChannel. Parent keeps port1. Transfer ships port2 into a real iframe document. Then send on the port, try a clone, try moving the same handle again.

The lab needs JavaScript in this page.

Check

After iframe.contentWindow.postMessage("init", origin, [port2]), where does the iframe read the port?

You call structuredClone(port2) with no transfer list. What happens?

You transferred port2. What is the original port2 object now?

Why must a MessagePort be listed in the transfer list?

The iframe now holds the transferred port. Do later messages on that pipe check origin?

You already transferred port2. You pass that same object in a new transfer list. What happens?

Primary source

Read the three-line handoff in HTML Living Standard §9.4.1 (otherWindow.postMessage('hello', 'https://example.com', [channel.port2])). Then the receiver side in MDN: Using channel messaging (event.ports[0]).

Ask the teacher

If clone-vs-move is still mushy — especially “why isn’t the port just event.data?” — ask. Next: lesson 4 — when a dedicated worker’s implicit port is enough, and a short playbook for choosing or rejecting a pair. Pocket cards: entangled ports, port API, transfer.