与iframe进行跨域通信时,Async/Await回答onMessage事件 [英] Async/Await answer onMessage event in cross-domain communication with an iframe

查看:92
本文介绍了与iframe进行跨域通信时,Async/Await回答onMessage事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个iframe,该iframe正在与其父窗口进行通信,以通过postMessage设置并获取一些必要的Cookie.方法.

I have an iframe, which is communicating with its parent window to set and get some essential cookies via postMessage method.

首先,iframe应用程序中的一个函数从父窗口请求Cookie A.

At first a function in the iframe application requests Cookie A from the parent window.

    function requestCommunication(topic, customerId) {

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

            console.log(cookieAvailable());

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

cookieAvailable()触发从iframe到父窗口的消息.反过来,窗口返回cookie及其数据作为字符串.通过使用以下命令完成此操作:

cookieAvailable() triggers the message from the iframe to the parent.window. In turn, the window returns the cookie with its data as string. This gets done by using the following:

 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)
    }    

我不知道如何正确使用promise将其移交给我的初始触发函数.我将不胜感激.

I don't get how to use the promise correctly to hand it over to my initial trigger function. I would appreciate any support.

推荐答案

您的代码中存在明显的问题和反模式. cookieAvailable将返回一个Promise,因此您的支票if(!!cookieAvailable()) {将始终是真实的.您将要等待该Promise解决,然后再检查是否确实存在cookie.

There are obvious problems and anti-patterns in your code. cookieAvailable will return a Promise, so your check if(!!cookieAvailable()) { will always be truthy. You will want to wait for that Promise to resolve before checking if there is indeed a cookie available.

但是实际上,您的cookieAvailable函数返回的是Promise包装器,没有任何内容:如果thisChatClient.cookie.getCookieData确实返回了Promise,则直接将其返回,无需将其包装在Promise中.
而且,如果返回的是同步结果,则只能通过将其包装在Promise中来放松

But actually, your cookieAvailable function returns a Promise wrapper for nothing: If thisChatClient.cookie.getCookieData does return a Promise then return it directly, no need to wrap it in a Promise.
And if it returns a synchronous result, then you will only loose by wrapping it in a Promise

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


现在,所有这些都无法正确回答您的问题:两个代码块之间的链接根本不清楚.


Now all this can't help to make a proper answer to your question: The link between your two code blocks is not clear at all.

什么都不会调用任何函数.

Nothing calls neither functions.

您的getCookieData将等待MessageEvent,而不会让任何人知道它正在等待它.

Your getCookieData will be waiting for a MessageEvent, without letting anyone know that it is waiting for it.

我不确定您如何计划让iframe知道应该将包含此信息的消息发送到窗口,但这是您必须考虑的事情.

I'm not sure how you did plan on letting your iframe know that it should send a message with this information to your window, but that's something you must consider.

但是在去那里之前,我应该指出:尽管很诱人,但是将事件包装在Promises中通常不是一个好主意.

But before going there I should note: as tempting as it could be, wrapping events in Promises is generally a bad idea.

事件和承诺是不同的事物,后者应仅解决一次,而前者可能会多次触发,并且来自不同的来源.

Events and Promises are different things, the latter should resolve only once while the former may fire multiple times, and from different sources.

IMM,只有在您确定该事件只会触发一次时,才这样做.有了MessageEvent,您就遥不可及了.
您的用户很可能在其浏览器上具有扩展名,该扩展名将使用postMessage作为通信方式.如果将此扩展名添加到所有iframe上,则您的代码已损坏.

IMM it is only good to do so when you are sure the event will fire only once. With the MessageEvent, you are far from knowing it.
Your user may very well have an extension on their browser that will use postMessage as a means for communication. If this extension is added on all iframes, your code is broken.

相反,您应该检查 MessageChannel API ,这将为您提供沟通的方式,可以确保您将是唯一使用的人.
我认为此答案不是解释此API如何工作的正确位置,但请查看

Instead, you should check the MessageChannel API, which will offer you mean of communication that you can be sure you'll be the only ones using.
I don't think this answer is the right place to explain how this API works, but have a look at this overview which explains the very basics.

由于您将确保可以控制两端,因此您可以从那里建立一个基于Promise的系统.

Since you'll be sure to be in control of both ends, from there you may set up a Promise based system.

在主页上,您将准备MessageChannel对象,并在侦听响应的同时将其发送到iframe.当此响应到来时,您将能够解决您的诺言.

From your main page, you'll prepare the MessageChannel object, and send it to the iframe while listening for a response. When this response will come, you'll be able to resolve your Promise.

在iframe中,您将在窗口上添加一个侦听器以捕获MessageChannelPort.发生这种情况时,您将向您的服务询问cookie,然后通过MessageChannel的端口将其发送回去.

From your iframe, you'll add a listener on the window to trap the MessageChannelPort. When this happens, you'll ask your service for the cookie and send it back through the MessageChannel's port.

即使在交换过程中主窗口上出现一条消息,您也可以确定它不会是您正在等待的消息.

Even if a message comes on your main's window during this exchange, you can be sure that it won"t be the one you are waiting for.

// 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>

这篇关于与iframe进行跨域通信时,Async/Await回答onMessage事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆