本文介绍了双向使用 MessageChannel() 处理页面和 iframe 之间的多条消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用 MessageChannel() 在页面和 iframe 之间传递消息.在我的场景中,iframe 是通信发起者,包含它的页面接收、转换并响应 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.

在我实现系统时,我首先获取并保存了对传递给 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;
  }

我正在通过 parentPort 运行从 iframe 到父级的所有后续通信:

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?

这里是来源.

编辑 - 我一定误解了示例的意图 MDN:

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 = '';
    }
  }

这是在 Kaiido 的 Plunker 示例中重构的.

This is refactored in Kaiido's Plunker example.

推荐答案

这不是很清楚你在做什么,甚至在 github 上阅读你的代码......

That's not really clear what you are doing, even reading your code on github...

您似乎混淆了 WindowObject.postMessage 方法和 MessagePort 方法.WindowObject 的一个应该只使用一次,在协商部分.
因此,让我们退后一步,更基本地解释应该如何理解事物:

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:

您应该将消息渠道视为 Yoghurt-pot Telephone® .

You should think of message channels as a Yoghurt-pot Telephone® .

                   –––––                         –––––
                po(r)t1 |~~~~~~~~~~~~~~~~~~~~~~~| po(r)t2
                   –––––                         –––––

  • 必须由一个用户创建.
  • 然后,他会将(转让)一个 po(r)ts 给另一个用户.
  • 一旦完成,每个用户只能访问自己的 po(r)t.
  • 因此,为了能够接收来自其他用户的消息,他们必须注意自己的 po(r)t(附加事件处理程序).
  • 并且要发送消息,他们会在他们仍然拥有的唯一 po(r)t 内说出消息 (postMessage),与他们正在收听的相同.
    • 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. 生成 Yoghurt-pot phone® 又名 MessageChannel.

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

      var yoghurt_phone = new MessageChannel();
      

    • 保留一个 po(r)t 并将另一个给另一个用户(iframe).为此,我们使用 WindowObject.postMessage 方法,该方法与我们将用于通过 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
      );
      

    • 从框架中接收 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];
          // ...
      

    • 从现在开始,每个用户都有自己的 po(r)t,而且只有一个 po(r)t.所以在两端,你需要在自己的单个 po(r)t 上设置监听器.

    • 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;
      

    • 然后当两个用户中的一个想要告诉另一个用户时,他们会根据自己的 po(r)t 来做.

      // from main doc
      mains_yoghurt_pot.postMessage('hello frame');
      
      // or from iframe doc
      frames_yoghurt_pot.postMessage('hello main');
      

    • 将 OP 的代码固定为 plunker.

      这篇关于双向使用 MessageChannel() 处理页面和 iframe 之间的多条消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-03 09:53