Lesson 0005 · ~12 minutes
One skill: create a
MessageChannel. Keep
port1. Transfer
port2. Then talk on the
MessagePort.
You can say this: “I wait for ready. I transfer
port2. I keep port1. After that, this
conversation is on the port. The port has no
targetOrigin.”
Any holder of your WindowProxy can send to the window.
You filter with
event.origin.
You want one private conversation with one iframe.
A MessageChannel is two ports that are paired. (MDN)
const channel = new MessageChannel();
channel.port1.onmessage = (event) => {
// event.data
};
otherWindow.postMessage({ type: "port" }, "https://widget.example", [
channel.port2,
]);
You keep port1.
You
transfer
port2. You already know transfer from the Structured
Clone topic.
After the transfer, this page cannot use
port2.
(MDN)
Wait for ready first.
The window message that carries the port still needs a real
targetOrigin. Check
event.origin and
event.source on that message.
window.addEventListener("message", (event) => {
if (event.origin !== "https://app.example") return;
const port = event.ports[0];
if (!port) return;
port.onmessage = (e) => {
// e.data — talk on the port now
};
port.postMessage({ type: "port-ready" });
});
The port is
event.ports[0].
(MDN)
If you use addEventListener on the port, call
port.start(). If you set
onmessage, the browser starts the port.
(MDN)
port.postMessage(data) has no
targetOrigin.
The port is the check. Who holds the port can send.
On a port message,
event.origin is the empty string.
(HTML Standard)
Do not treat that field as the child origin.
This is why the first window send still names a real
targetOrigin. That send is how the child
gets the port.
const iframeRef = useRef(null);
const portRef = useRef(null);
function givePort() {
const channel = new MessageChannel();
channel.port1.onmessage = (event) => {
// event.data
};
iframeRef.current.contentWindow.postMessage(
{ type: "port" },
"https://widget.example",
[channel.port2],
);
portRef.current = channel.port1;
}
Call givePort after ready. Then send on
portRef.current.
parent child | | | ready | | <--------------------| | | | postMessage(..., | | [port2]) | | -------------------->| event.ports[0] | | | port1.postMessage | | ====================>| port.onmessage | |
The child below sends ready when it loads its listener.
true.
held. The parent log must show a message from
the port.
port: line must change.
window: line must change. The port line must not
change for that send.
port2 is gone.
Do the five steps first. Then answer these questions.
You need a private MessageChannel with one iframe.
You already transferred port2. You call port2.postMessage here.
The window message carries a port. What do you keep?
A message arrives on the port.
You use addEventListener on the port.
port1. Transfer port2 after
ready.
event.ports[0].
targetOrigin.
targetOrigin.
event.origin on the port is empty.
onmessage starts the port.
addEventListener needs start().
MDN — Using channel messaging.
That sample waits for load. This track waits for
ready, then transfers.
Then
HTML §9.4.1.2.