Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
113 views
in Technique[技术] by (71.8m points)

javascript - Using MessageChannel() bidirectionally for multiple messages between page and iframe

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

  1. Generate The Yoghurt-pot telephone? a.k.a MessageChannel.

    var yoghurt_phone = new MessageChannel();
    
  2. 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
    ); 
    
  3. 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];
        // ... 
    
  4. 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;
    
  5. 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...