在页面和iframe之间双向使用MessageChannel()处理多个消息

jch*_*tof 0 javascript iframe message-channel

我正在使用MessageChannel()在页面和iframe之间传递消息。在我的场景中,iframe是通信发起方,包含它的页面接收,转换并响应iframe。

在实施系统时,我首先获取并保存了对传递给iframe的端口的引用,将其缓存并继续用于以后的每次通信。

iframe:

 window.onmessage = (e) => {
    console.log("iframe port established");
    //using this port for all following communications
    parentPort = e.ports[0];
    onmessage = establishedConnectionHandler; 
  }
Run Code Online (Sandbox Code Playgroud)

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

parentPort.postMessage({command, guid, message});
Run Code Online (Sandbox Code Playgroud)

即使文档指出消息通道是一次性通信,这似乎仍然有效,并且使发起通信变得很方便。

我的问题-是受支持的功能还是我正在利用未定义的行为?

这是来源。

编辑-我必须误解了示例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 = '';
    }
  }
Run Code Online (Sandbox Code Playgroud)

在Kaiido的Plunker示例中对此进行了重构。

Kai*_*ido 7

即使在github上阅读代码,也不清楚您在做什么。

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


您应该将消息渠道视为酸奶罐电话® [pdf]

                   –––––                         –––––
                po(r)t1 |~~~~~~~~~~~~~~~~~~~~~~~| po(r)t2
                   –––––                         –––––
Run Code Online (Sandbox Code Playgroud)
  • 一个用户必须创建它。
  • 然后,他会给(传输宝(R)的TS的其他用户)之一。
  • 完成此操作后,每个用户只能访问自己的po(r)t。
  • 为了能够接收来自其他用户的消息,他们必须将注意力放在自己的po(r)t上(附加事件处理程序)。
  • 为了发送消息,他们会说消息(postMessage)在他们仍然拥有的唯一地点内,就像他们正在收听一样。

因此,添加一些代码行,您应该做的是:

  1. 生成酸奶罐电话 ®(又名MessageChannel)。

    var yoghurt_phone = new MessageChannel();
    
    Run Code Online (Sandbox Code Playgroud)
  2. 保留其中一个,然后将另一个交给其他用户(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
    ); 
    
    Run Code Online (Sandbox Code Playgroud)
  3. 从框架上取下电源并保持紧紧。

    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];
        // ... 
    
    Run Code Online (Sandbox Code Playgroud)
  4. 从现在开始,每个用户都有自己的po(t)t,只有一个po(r)t。因此,在两端,您都需要在自己的单个po(r)t上设置侦听器。

    // from main doc
    mains_yoghurt_pot.onmessage = frameTalksToMe;
    
    Run Code Online (Sandbox Code Playgroud)

    // from iframe doc
    frames_yoghurt_pot.onmessage = mainTalksToMe;
    
    Run Code Online (Sandbox Code Playgroud)
  5. 然后,当两个用户之一要告诉另一个用户时,他们将使用自己的po(r)t进行操作

    // from main doc
    mains_yoghurt_pot.postMessage('hello frame');
    
    Run Code Online (Sandbox Code Playgroud)

    // or from iframe doc
    frames_yoghurt_pot.postMessage('hello main');
    
    Run Code Online (Sandbox Code Playgroud)

固定OP的代码是一个小问题。