接受的答案并没有解决原来的问题:
w = window.open();
w.location.href="child.html";
// block until child has finished loading... how?
w.doSomething();
为了解决这个问题,我们需要更多地了解页面加载是如何在后台进行的。实际上它是异步的,因此当您编写w.location.href="child.html";
并w.doSomething();
立即调用时,它不会等到新页面加载。虽然浏览器开发人员很好地解决了 iframe 的加载问题,但对于子窗口却并非如此。没有用于此的 API,因此您所能做的就是编写某种解决方法。您可以做的是从子窗口的卸载事件侦听器中使用正确的延迟函数:
w.addEventListener("unload", function (){
defer(function (){
w.doSomething();
});
});
像往常一样,客户端 js 开发,每个浏览器的工作方式完全不同。
最好的解决方案是使用 defer 函数,它会在子窗口的文档处于加载就绪状态时调用回调,您可以在其中添加加载处理程序。如果在此之前调用回调,那么在当前浏览器中,新文档尚未创建,因此加载处理程序将添加到旧文档中,稍后将被新文档替换,因此加载处理程序将迷路了。唯一的例外是 Firefox,因为该浏览器将加载处理程序添加到窗口中。如果浏览器在加载 readyState 后调用 defer 回调,那么在当前的某些浏览器中,页面实际加载后甚至可能会有超过 2500 毫秒的延迟。我不知道为什么某些浏览器会因子窗口文档加载的某些延迟而产生如此巨大的延迟。找了一会儿,但没有找到任何答案。一些浏览器没有任何“加载”延迟,因此您所能做的就是使用“延迟”延迟,并希望最好。根据我的测试结果,基于 MessageChannel 的解决方案是最好的多浏览器“加载”延迟:
function defer (callback) {
var channel = new MessageChannel();
channel.port1.onmessage = function (e) {
callback();
};
channel.port2.postMessage(null);
}
因此,您可以执行以下操作:
w.addEventListener("unload", function (){
// note: Safari supports pagehide only
defer(function (){
if (w.document.readyState === "loading")
w.addEventListener("load", function (){
w.doSomething();
});
else
w.doSomething();
});
});
如果你想支持 Safari,那么你应该使用 pagehide 而不是 unload。该pagehide事件从IE 11的支持,所以如果你想支持更老的浏览器,那么你必须同时使用卸载和pagehide,只有其中一人开始延迟如果两者都可用。
var awaitLoad = function (win, cb){
var wasCalled = false;
function unloadListener(){
if (wasCalled)
return;
wasCalled = true;
win.removeEventListener("unload", unloadListener);
win.removeEventListener("pagehide", unloadListener);
// Firefox keeps window event listeners for multiple page loads
defer(function (){
win.document.readyState;
// IE sometimes throws security error if not accessed 2 times
if (win.document.readyState === "loading")
win.addEventListener("load", function loadListener(){
win.removeEventListener("load", loadListener);
cb();
});
else
cb();
});
};
win.addEventListener("unload", unloadListener);
win.addEventListener("pagehide", unloadListener);
// Safari does not support unload
});
w = window.open();
w.location.href="child.html";
awaitLoad(w, function (){
w.doSomething();
});
如果支持 Promises 和 async 函数,那么您可以使用以下内容:
w = window.open();
await load(w, "child.html");
w.doSomething();
但这是一个不同的故事......