Javascript 正在等待子窗口加载完成

Javascript 正在等待子窗口加载完成,javascript,Javascript,是否有一个简单的钩子来检测脚本打开的窗口是否已完成加载?基本上,我想要的是onLoad()hook的等价物,但我不能直接设置它——假设子文档是给定的,我实际上不能在其中放入任何自己的代码 例如,假设我有以下两个文件: parent.html: <html> <head> <title>Parent</title> </head> <script type="text/javascript"> va

是否有一个简单的钩子来检测脚本打开的窗口是否已完成加载?基本上,我想要的是
onLoad()
hook的等价物,但我不能直接设置它——假设子文档是给定的,我实际上不能在其中放入任何自己的代码

例如,假设我有以下两个文件:

parent.html

<html>
  <head>
    <title>Parent</title>
  </head>
  <script type="text/javascript">
    var w;
    function loadChild() {
      w = window.open();
      w.location.href="child.html";
      // block until child has finished loading... how?
      w.doSomething();
    } 
  </script>
</html>
<body>
  I am a parent window. <a href="javascript:loadChild()">Click me</a>.
</body>
<html>
  <head>
    <title>Child</title>
  </head>
  <script type="text/javascript">
    function doSomething() {
      alert("Hi there");
    }
  </script>
</html>
<body>
  I am a child window
</body>
由于setting location.href是非阻塞的,
w.doSomething()
尚未定义,因此
doSomething()
调用中断。如何检测孩子已完成加载?

如何

parent.html:

<html>
<head>
<title>Parent</title>
</head>
<script type="text/javascript">
  var w;
  function loadChild() {
    w = window.open();
    w.location.href="child.html";
    // like this (with jquery)
    $(w).ready(function()
    {
      w.doSomething();
    });
  } 
</script>
</html>
<body>
  I am a parent window. <a href="javascript:loadChild()">Click me</a>.
</body>

父母亲
var-w;
函数loadChild(){
w=window.open();
w、 location.href=“child.html”;
//像这样(使用jquery)
$(w).ready(函数()
{
w、 doSomething();
});
} 
我是一个家长。

如果新打开的窗口的位置是同一原点,则此操作有效:

var w = window.open('child.html')
w.addEventListener('load', w.doSomething, true); 

接受的答案不能解决原始问题:

  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函数,该函数在子窗口的文档位于加载readyState时调用回调,您可以在其中添加加载处理程序。如果在此之前调用回调,则在当前浏览器中,新文档尚未创建,因此加载处理程序将添加到旧文档中,稍后将被新文档替换,因此加载处理程序将丢失。唯一的例外是Firefox,因为该浏览器将加载处理程序添加到窗口中。如果浏览器在加载readyState后调用defer回调,那么在当前的一些浏览器中,页面实际加载后的延迟甚至可能超过2500毫秒。我不知道为什么有些浏览器会因为子窗口文档加载的延迟而产生如此巨大的延迟。我找了一会儿,但没有找到任何答案。一些浏览器没有任何“加载”延迟,因此通过这些,您所能做的就是使用“延迟”延迟,并希望达到最佳效果。根据我的测试结果,基于MessageChannel的解决方案是最好的多浏览器“加载”延迟:

因此,您可以执行以下操作:

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。因此,如果您想支持更旧的浏览器,则必须同时使用unload和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();
});
如果支持承诺和异步函数,则可以使用以下内容:

w = window.open();
await load(w, "child.html");
w.doSomething();

但这是另一回事……

似乎什么都没做(我以前没有见过
$
操作符(我大部分时间都用Java);它应该做什么?Chrome JavaScript调试器给了我
未捕获的异常引用error:$is not defined
。哦,交叉注释。是的,jQuery,这就解释了为什么我没有看到它。看起来应该有某种方法可以用DOM来完成。如果不使用JS框架,最好使用gunderwonder的解决方案。正如他所说,“addEventListener”在IE中不受支持,但您可以进行浏览器检查,如果是IE,则使用microsofts实现的adding event listener=>“w.attachEvent('onload',doSomething);”您能否澄清“相同来源”?它似乎不适用于本地框上的
文件://
URL,但这可能是一个安全问题?是的,可能是。在浏览器中,相同的来源基本上意味着目标必须位于相同的主机和相同的协议上。您是否将其与
http://
混合使用?我忘了添加
addEventLister
不是正确的支持移植到IE中,因此使用gabtub建议的jQuery(或另一个JS框架,修复浏览器在事件处理方面的不兼容性)可能是一个好主意……不是混合,我猜Chrome只是不考虑两个<代码>文件:///</代码> URL同根,我不能让IE7在本地文件上运行脚本……也许我应该用一个正在运行的服务器试试这个。rictive(在某些情况下,只是坏掉了)。请使用合适的web服务器进行尝试,看看这是否解决了问题。此外,请尝试检查IE/Chrome中的控制台是否有任何错误消息。您保存了我的一天,谢谢!我正在寻找一种方法来关闭弹出窗口中引发的事件的弹出窗口,但我总是收到这样的警告“只有创建窗口的脚本才能关闭它”。但这段代码允许我在开瓶器中放置一个eventListener!因此,对于每个正在寻找方法的人来说,这是go@Nenriyw………:-)请注意,您不能通过提供错误的地址来访问浏览器错误页,例如Chrome错误页。它们与opener页的来源不同。目前还没有解决办法。我正在使用window.open和Karma进行e2e测试项目,但部分原因是我不得不停止。我可能稍后会再次启动它。@Nenri同样的原因ng适用于每个跨帧跨源请求。例如,如果
www.example.com
在新窗口中打开
sub.example.com
,则您将无法访问该窗口并等待页面加载。仅禁用浏览
w = window.open();
await load(w, "child.html");
w.doSomething();