如何检查打开的跨域窗口是否已准备好接收postmessage?

时间:2017-11-14 09:44:25

标签: javascript google-chrome cross-domain

我从另一个域启动一个URL,然后将postMessage发送到它

const child = window.open("http://urlfromanotherdomain.com");
child.postMessage("you cant handle the message", "*");

我启动的子窗口中的JavaScript代码按如下方式注册其兴趣:

window.onmessage = function(ev) {window.console.log(ev);}

问题在于,有时在子窗口中运行的代码太多,以至于它能够注册它没有收到已发布消息的兴趣。

如何可靠地知道跨域子窗口已准备好接收消息?我试图注册child.onload,但这不会触发,因为它是跨域的。还有什么比将参数传递给window.open,可以保证传递消息吗?

可能相关的其他信息:

  • 我正在使用Chrome的第62版。
  • 我最终使用跨域窗口的真正原因是因为我想确保在子窗口中获得一个新的渲染线程,因为它正在进行的渲染非常繁重。如果我使它成为相同的来源,Chrome似乎重复使用渲染器进程,因此使用相同的线程。

1 个答案:

答案 0 :(得分:0)

我找不到直接执行此操作的方法。困难在于无法在跨域窗口上侦听事件,因此无法直接知道何时加载完成并准备接受您发布的消息。

一种快速的解决方法是使用超时:

 var child = window.open( url, winId );
 setTimeout( function(){
     child.postMessage(data, url);
 }, 1000);

当然,如果孩子的加载速度真的很慢,则不能保证以这种方式。

如果您有权访问子代代码,则可以使用上面的“ setInterval”并继续调用postMessage,直到子代使用“ event.source.postMessage()”返回消息为止,如MDN page for postMessage中所述。父级还需要设置一个消息侦听器。父级收到消息后,您便会清除间隔。我还会设置一个限制,以使间隔在尝试一定次数后停止运行。

如果您无法访问子代码,则还有另一种方法,涉及使用iFrame。拥有iframe后,就可以知道它何时完成加载(即使它是从其他域加载的)。这就是我的工作方式:

  1. 使用js,css和html创建一个新的html页面,并将其命名为“ child-container.html”:

window.loadChildApp = function(url, json, title){
            window.document.title = title;
            var iframe = document.querySelector('#myIframe');
            iframe.src = url;
            document.querySelector('#loadingDiv').style.display = 'none';
            iframe.addEventListener('load', function(){
                iframe.contentWindow.postMessage(JSON.stringify(json), url);
            });
        }
#myIframe{
        height: 100%;
        width: 100%;
        border: none;
        margin: none;
    }
    
     #loadingDiv{
        height: 100%;
        width: 100%;
        margin: auto;
        padding: none;
    }
<div id="loadingDiv">Loading ... </div>
<iframe id="myIframe"  >

  1. 在您的父页面中,打开子容器html,并附加一个加载侦听器。加载时,您调用loadChildApp函数,该函数将完成加载iframe的实际工作,等待其完成,然后发布消息。

        let win = window.open( 'child-container.html', key );
        win.addEventListener('load', function () {
            win.loadChildApp(url, data, title);
        });
    

此技术的一个次要缺点是不会向用户显示孩子的真实标题和网址(在地址栏中)。他们只会看到您给的标题和child-container.html的网址