How do I check if the opened cross domain window is ready to receive postmessage?

戏子无情 提交于 2021-01-01 06:25:25

问题


I launch a URL from another domain and then postMessage to it

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

The JavaScript code, in the child window I launch, registers its interest as follows:

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

The problem is that sometimes there's so much code to run in the child window before it's able to register interest that it doesn't receive the posted message.

How do I reliably know that the cross-domain child window is ready to receive messages? I tried to register child.onload, but that doesn't fire as it's cross-domain. Is there anything else like passing a parameter to window.open that can guarantee the delivery of the message?

Additional information that may be relevant:

  • I'm using version 62 of Chrome.
  • The real reason I'm ending up with a cross-domain window is because I want to ensure I get a new rendering thread in the child window as the rendering it is being done in is quite heavy. If I make it the same origin, Chrome seems to reuse the renderer process and hence the same thread.

回答1:


I have found no way to do this directly. The difficulty is that can't listen to events on cross-domain windows, so there is no direct way to know when it's finished loading and ready to accept your posted message.

A quick work-around is to use a timeout:

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

Of course this way is not guaranteed if the child is really slow in loading.

If you have access to the child code, then you use "setInterval" above and keep calling postMessage until the child returns back a message using "event.source.postMessage()" as explained in the MDN page for postMessage. The parent would also need to set up a message listener. Once the parent gets the message back, you clear the interval. I would also make a limit so interval stops running after a certain number of attempts.

If you can't access the child code, there is one other way, which involves using an iFrame. Once you have an iframe, you can know when it's finished loading (even if it's loading from a different domain). This is how I got it to work:

  1. Create a new html page with js, css, html like this and name it "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. In your parent page, open the child-container html, attach a load listener. When it loads you call the loadChildApp function, which will do the real work of loading the iframe, waiting for it to finish, then posting the message.

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

One minor downside of this technique is that the child's true title and url (in the address bar) will not be shown to the user. They will just see the title you gave and the url of the child-container.html



来源:https://stackoverflow.com/questions/47282352/how-do-i-check-if-the-opened-cross-domain-window-is-ready-to-receive-postmessage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!