Async / Await answer onMessage событие в междоменной связи с iframe - PullRequest
4 голосов
/ 03 апреля 2019

У меня есть iframe, который взаимодействует со своим родительским окном для установки и получения некоторых необходимых файлов cookie с помощью метода postMessage .

Сначала функция в приложении iframe запрашивает Cookie A изродительское окно.

    function requestCommunication(topic, customerId) {

            function cookieAvailable() {
                return new Promise((resolve) => resolve(getCookieData('cookieName'));
                });
            }

            console.log(cookieAvailable());

            if(!!cookieAvailable()) {
                //doStuff        
            }
     }

cookieAvailable() запускает сообщение из iframe в parent.window.В свою очередь, окно возвращает cookie с данными в виде строки.Это делается с помощью следующего:

 async function getCookieData(cookieName) {

        const {data} = await new Promise(resolve => {

            window.onmessage = (event) => {
                resolve(event);
            }
        });

        var cookieContent = JSON.parse(data);
        var cookieContentData = JSON.parse(cookieContent.data);

        return cookieContentData; //this returns the cookie data (in almost all cases)
    }    

Я не понимаю, как правильно использовать обещание, чтобы передать его моей начальной функции триггера.Буду признателен за любую поддержку.

1 Ответ

1 голос
/ 06 апреля 2019

В вашем коде есть очевидные проблемы и анти-паттерны.cookieAvailable вернет Обещание, поэтому ваш чек if(!!cookieAvailable()) { всегда будет правдивым.Вам следует подождать, пока это Обещание не будет выполнено, прежде чем проверять, действительно ли доступен файл cookie.

Но на самом деле ваша функция cookieAvailable возвращает упаковку Обещания даром: если thisChatClient.cookie.getCookieData действительно возвращает Обещание, то возвращайте его напрямую, нет необходимости заключать его в Обещание.синхронный результат, тогда вы проиграете, только обернув его в Обещание

async function requestCommunication(topic, customerId) {

  function cookieAvailable() {
    // this is already a Promise
    return thisChatClient.cookie.getCookieData('sess_au');
  }

  const isCookieAvailable = await cookieAvailable();

  if (!!isCookieAvailable) {

  }
}
requestCommunication().catch(console.error);

Теперь все это не может помочь сделать правильный ответ на ваш вопрос: связь между вашими блоками кодане совсем понятно.

Ничто не вызывает ни функции.

Ваш getCookieData будет ожидать MessageEvent, не сообщая никому, что он его ждет.

Я не уверен, как вы запланировали, чтобы ваш iframe знал, что он должен отправить сообщение с этой информацией в ваше окно, но это то, что вы должны рассмотреть.

Но прежде чем идти тудаЯ должен отметить: как бы заманчиво это ни было, упаковывать события в Promises, как правило, плохая идея.

События и Обещания - это разные вещи, последние должны разрешаться только один раз, в то время как первые могут срабатывать несколько раз и из разных источников.

IMM это хорошо делать только тогда, когда вы уверены, что событие сработает только один раз.С MessageEvent, вы далеки от его знания.
Ваш пользователь вполне может иметь расширение в своем браузере, которое будет использовать postMessage в качестве средства для общения.Если это расширение добавлено во все iframes, ваш код не работает.

Вместо этого вы должны проверить MessageChannel API , который предложит вам средство общения, которое вы можете быть уверены, что будете использовать только вы.
Я не думаю,этот ответ - правильное место, чтобы объяснить, как работает этот API, но взгляните на этот обзор , который объясняет самые основы.

Так как вы обязательно будете контролировать обаПосле этого вы можете настроить систему на основе Promise.

На главной странице вы подготовите объект MessageChannel и отправите его в iframe, ожидая ответа.Когда придет этот ответ, вы сможете выполнить свое Обещание.

В своем фрейме вы добавите в окно прослушиватель для перехвата MessageChannelPort.Когда это происходит, вы запрашиваете cookie-файл у своей службы и отправляете его обратно через порт MessageChannel.

Даже если во время этого обмена в вашем главном окне появляется сообщение, вы можете быть уверены, что оно не будетбудь тем, кого ты ждешь.

// Sets up a new MessageChannel
// so we can return a Promise
function getCookieData() {
  return new Promise((resolve) => {
    const channel = new MessageChannel();
    // this will fire when iframe will answer
    channel.port1.onmessage = e => resolve(e.data);
    // let iframe know we're expecting an answer
    // send it its own port
    frame.contentWindow.postMessage('getCookie', '*', [channel.port2]);  
  });
}

frame.onload = async e => {
  const frameHasCookie = await getCookieData();
  console.log(frameHasCookie);
};

frame.src = generateFrameSRC();

function generateFrameSRC() {
  // The content of your iframe
  const cont = `
<html>
  <head>
    <script>
      const originClean = "null";
      onmessage = async e => {
        // only if it's the origin we expected 
        // and if it does send a  MessagePort 
        // and the message is "getCookie"
        if(e.origin === originClean && e.ports && e.data === "getCookie") {
          const data = await asyncData();
          // respond to main window
          e.ports[0].postMessage(data);
        }
      };
      function asyncData() {
        return new Promise(resolve => 
          setTimeout(() => resolve("the data"), 1000)
        );
      }
    <\/script>
  </head>
  <body>
    hello
  </body>
</html>`;
  return 'data:text/html,' + encodeURIComponent(cont)
}
<iframe id="frame"></iframe>
...