Использование MessageChannel() двунаправленно для нескольких сообщений между страницей и iframe

Я использую 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; 
  }

Я запускаю все последующие сообщения от iframe к родителю через parentPort:

parentPort.postMessage({command, guid, message});

даже несмотря на то, что в документах указано, что канал сообщений является одноразовым обменом данными, это работает и делает инициирование обмена данными удобным.

Мой вопрос - это поддерживаемая функциональность или я использую неопределенное поведение?

Вот источник.

Изменить - я, должно быть, неправильно понял цель примера 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 = '';
    }
  }

Это отражено в примере Кайидо Плункер.

1 ответ

Решение

Не совсем понятно, что вы делаете, даже читая ваш код на github...

Вы, кажется, путаете метод WindowObject.postMessage и метод MessagePort. Объект WindowObject следует использовать только один раз, в части согласования.
Итак, давайте сделаем шаг назад, чтобы более подробно объяснить, как все должно быть понято:


Вы должны думать о каналах сообщений как о Yoghurt-pot Telephone® [pdf].

                   –––––                         –––––
                po(r)t1 |~~~~~~~~~~~~~~~~~~~~~~~| po(r)t2
                   –––––                         –––––
  • Один пользователь должен создать его.
  • Затем он передаст (передаст) один из по (т) другим пользователям.
  • Как только это сделано, каждый пользователь имеет доступ только к своему собственному po (r) t.
  • Таким образом, чтобы иметь возможность получать сообщения от другого пользователя, он должен приложить все свои усилия (прикрепить обработчик событий).
  • А чтобы отправлять сообщения, они будут говорить сообщение (postMessage) внутри единственного сообщения, которое они все еще имеют, то же самое, что они слушают.

Итак, чтобы добавить несколько строк кода, вам нужно сделать следующее:

  1. Создайте телефон Yoghurt-pot® aka MessageChannel.

    var yoghurt_phone = new MessageChannel();
    
  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
    ); 
    
  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];
        // ... 
    
  4. Отныне каждый пользователь имеет свой собственный po (r) t и только один po (r) t. Таким образом, на обоих концах вам нужно настроить слушателей на их собственный po (r) t.

    // from main doc
    mains_yoghurt_pot.onmessage = frameTalksToMe;
    

    // from iframe doc
    frames_yoghurt_pot.onmessage = mainTalksToMe;
    
  5. И затем, когда один из двух пользователей хочет что-то сказать другому, они поступают по собственному желанию.

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

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

Исправлен код ОП в качестве плунжера.

Другие вопросы по тегам