I'm using MessageChannel() to pass messages between a page and iframe. In my scenario, the iframe is the communications initiator and the page containing it receives, transforms and responds back to the iframe.
As I was implementing the system I at first took and saved a reference to the port passed to the iframe, cached it and continue to use it for each subsequent communication.
iframe:
window.onmessage = (e) => {
console.log("iframe port established");
//using this port for all following communications
parentPort = e.ports[0];
onmessage = establishedConnectionHandler;
}
I'm running all subsequent communications from the iframe to the parent through parentPort:
parentPort.postMessage({command, guid, message});
even though the docs state that the message channel is a one-shot communication this appears to work and makes initiating communications convenient.
My question - is this supported functionality or am I exploiting undefined behavior?
Here is the source.
Edit - I must have misunderstood the intent of the example MDN:
button.onclick = function(e) {
e.preventDefault();
var channel = new MessageChannel();
otherWindow.postMessage(textInput.value, '*', [channel.port2]);
channel.port1.onmessage = handleMessage;
function handleMessage(e) {
para.innerHTML = e.data;
textInput.value = '';
}
}
This is refactored in Kaiido's Plunker example.
That's not really clear what you are doing, even reading your code on github...
You seem to be confusing the WindowObject.postMessage method and the MessagePort's one. WindowObject's one should be used only once, at the negotiation part.
So let's take a step back to explain more basically how things should be understood:
You should think of message channels as a Yoghurt-pot Telephone® [pdf].
––––– –––––
po(r)t1 |~~~~~~~~~~~~~~~~~~~~~~~| po(r)t2
––––– –––––
- One user has to create it.
- Then he will give (transfer) one of the po(r)ts to the other user.
- Once this is done, each user has only access to its own po(r)t.
- So to be able to receive messages from the other user, they have to put their ear on their own po(r)t (attach an event handler).
- And to send messages, they will say the message (postMessage) inside the only po(r)t they still have, the same they are listening to.
So to add some lines of code, what you should do is:
Generate The Yoghurt-pot telephone® a.k.a MessageChannel.
var yoghurt_phone = new MessageChannel();
Keep one of the po(r)t and give the other one to the other user (iframe). To do this, we use the WindowObject.postMessage method, which is not the same as the one we'll use to communicate through the MessagePorts.
mains_yoghurt_pot = yoghurt_phone.port1;
frame.contentWindow.postMessage( // this is like a physical meeting
'look I made a cool Yoghurt-phone', // some useless message
'*', // show your id?
[yoghurt_phone.port2] // TRANSFER the po(r)t
);
From the frame, receive the po(r)t and keep it tight.
window.onmessage = function physicalMeeting(evt) {
if(evt.ports && evt.ports.length) { // only if we have been given a po(r)t
frames_yoghurt_pot = evt.ports[0];
// ...
From now on, each user has its own po(r)t, and only a single po(r)t. So at both ends, you need to setup listeners on their own single po(r)t.
// from main doc
mains_yoghurt_pot.onmessage = frameTalksToMe;
// from iframe doc
frames_yoghurt_pot.onmessage = mainTalksToMe;
And then when one of the two users wants to tell something to the other one, they'll do from their own po(r)t.
// from main doc
mains_yoghurt_pot.postMessage('hello frame');
// or from iframe doc
frames_yoghurt_pot.postMessage('hello main');
Fixed OP's code as a plunker.