问题
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:
- 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" >
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