Chrome浏览器中的页面重新加载会在重新加载页面之前不必要地触发绑定事件

22
希望有人能给出一个好的答案: 为什么Chrome(14.0)在我刷新页面时会触发文档准备就绪和窗口加载事件?注意,我不是在谈论新页面加载时会发生什么,而是在它加载之前。请参见以下代码:
<form name="form1" method="post" action="tmp.aspx?a=1" id="form1">
<script type="text/javascript">

    $(document).ready(function () { console.log('document/ready' + new Date()); });

    $(window).load(function () { console.log('window/load' + new Date()); });

</script>

<a href="tmp.aspx?a=1">tmp</a>
</form>
当我第一次访问页面时,控制台会输出两个内容,一个是document/ready(文档/就绪)的输出,另一个是window/load(窗口/加载)的输出。当我刷新页面时,还会有两个快速的输出,紧接着就会有两个来自新页面视图的输出。但如果我直接点击链接(tmp.aspx)返回到同一页,这种情况就不会发生。
我相信这有一个很好的解释。
编辑: 对于额外调用的$(document).ready()和$(window).load()方法,它们是在页面刷新之前被调用的。因此,第一次加载页面时,这些方法只会被调用一次,然后我点击刷新按钮,在页面重新加载之前,这些方法会再次被调用。在页面刚刚被重新加载后,这些方法会被调用第三次。

这是一个iframe吗?因为我认为我已经注意到了类似的行为,但是对于像Facebook的小部件之类的东西。 - Achshar
还有,为了消除变量,您可以尝试不使用jQuery吗?也许是jQuery搞乱了它...在纯JavaScript中为body添加事件监听器。这应该可以缩小问题范围。 - Achshar
我也遇到了这个问题 - 真的很烦人。我还发现哈希更改事件会导致 document.ready 不必要地触发。 - asgeo1
也许Chrome认为它可以展示缓存的页面,但最终决定不展示:所以当你刷新时,就会从缓存版本快速触发ready事件,然后页面实际上会重新加载并且触发"真正的" ready事件? - Andreas Louv
你能提供一个 jsfiddle 吗? - Kiquenet
6个回答

7

观察到的行为发生在14.0.835.202版本上,编辑:(在Windows Seven x64上)

这不是jQuery的问题:DOMContentLoaded在页面卸载之前又被触发了一次。

进行简单测试以检查此问题:

 function startpage() {   
     console.log('page loaded');
   }   

   function unloadPage(){
       console.log("page unloaded");
   }
document.addEventListener("DOMContentLoaded", startpage, false);
window.onbeforeunload = unloadPage;

您需要在刷新后看到以下内容:
page loaded
page loaded // should not be here and is not on Firefox.
page unloaded
loaded

在您的控制台(保持持久性)中

我认为这只是Chrome的一个bug,而不是控制台的一个bug,因为时间戳证明它不是一个重复项。

编辑:相同版本的Chrome但运行在OSX上似乎没问题(见下面的评论)。这倾向于证实这是一个bug。


1
OSX 10.6.7 上测试了 Chrome 14.0.835.202,未能重现错误。日志按预期记录,每个请求周期都会显示 页面已加载;页面已卸载; - Daniel Mendel
感谢您的输入!所以OSX版本似乎没问题。我没有提到我的操作系统:我的测试是在Windows Seven x64上进行的。我会在有时间时在Windows XP(x86)上运行测试。 - mddw
1
问题确实在OSX上发生了 - 那是我正在使用的系统。 - asgeo1

3

关于测试的一些注释,我使用的是chrome 15.0.874.102和windows 7 x86:

根据我的理解,这是我用于测试的脚本:

<html>
    <head>
        <script language="javascript">
            var r = Math.floor(Math.random() * 101);

            function reloadLink() {
                console.log('----Reload Link----');
            }

            function startpage() {
                console.log('---Loaded. ID: ' + r + ' Time: '+new Date());
            }

            function unloadPage() {
                console.log('Un-loaded. ID: ' + r + ' Time: '+new Date());
            }

            document.addEventListener("DOMContentLoaded", startpage, false);
            window.onbeforeunload = unloadPage;

        </script>
        <title>Testing Chrome</title>
    </head>
    <body>
        <a href="" onclick="reloadLink();">Reload Page</a>
    </body>
</html>

以下是累积日志,每个新添加都以粗体突出显示:
在初始页面加载时,我得到:
---已加载。ID:68 时间:2011年10月25日星期二21:35:18 GMT+0100(GMT夏令时)
在HTML页面上聚焦后按F5:
---已加载。ID:68 时间:2011年10月25日星期二21:35:18 GMT+0100(GMT夏令时)
---已加载。ID:68 时间:2011年10月25日星期二21:35:18 GMT+0100(GMT夏令时)<-----
未加载。ID:68 时间:2011年10月25日星期二21:36:12 GMT+0100(GMT夏令时)
---已加载。ID:78 时间:2011年10月25日星期二21:36:12 GMT+0100(GMT夏令时)
按HTML页面上的链接重新加载页面:
---已加载。ID:68 时间:2011年10月25日星期二21:35:18 GMT+0100(GMT夏令时)
---已加载。ID:68 时间:2011年10月25日星期二21:35:18 GMT+0100(GMT夏令时)
未加载。ID:68 时间:2011年10月25日星期二21:36:12 GMT+0100(GMT夏令时)
---已加载。ID:78 时间:2011年10月25日星期二21:36:12 GMT+0100(GMT夏令时)
----重新加载链接----
未加载。ID:78 时间:2011年10月25日星期二21:38:25 GMT+0100(GMT夏令时)
---已加载。ID:22 时间:2011年10月25日星期二21:38:25 GMT+0100(GMT夏令时)
在控制台上聚焦后按F5:

---已加载。ID:68 时间:2011年10月25日21:35:18 GMT+0100(GMT夏令时)
---已加载。ID:68 时间:2011年10月25日21:35:18 GMT+0100(GMT夏令时)
未加载。ID:68 时间:2011年10月25日21:36:12 GMT+0100(GMT夏令时)
---已加载。ID:78 时间:2011年10月25日21:36:12 GMT+0100(GMT夏令时)
----重新加载链接----
未加载。ID:78 时间:2011年10月25日21:38:25 GMT+0100(GMT夏令时)
---已加载。ID:22 时间:2011年10月25日21:38:25 GMT+0100(GMT夏令时)

未加载。ID:22 时间:2011年10月25日21:41:53 GMT+0100(GMT夏令时)
---已加载。ID:15 时间:2011年10月25日21:41:54 GMT+0100(GMT夏令时)

从上面的内容可以看出,只有在直接重新加载页面时(我用箭头标注了异常),同时聚焦在页面本身时才会发生异常。
此外,如果你注意到异常的ID和时间戳,即使等待几秒钟然后按下F5,它们也是相同的,因此似乎代码并没有再次运行,但控制台由于某种原因记录了一份副本。


进一步添加到结论:

如果选择时间轴选项卡,并记录初始页面加载和F5重新加载,则会注意到两个写入控制台的函数仅运行一次,进一步证明可能是Chrome控制台的错误:

Screenshot 显示图片 - 时间轴 1(初始加载) Screenshot 显示图片 - 时间轴 2(F5重新加载)


谢谢,伙计。还有其他一些很好的解释,但由于我必须选择一个,所以这是最详细的解释,因此它得到了我的选择。干杯 - asgeo1

3
在Mac上的Chrome 13中,我没有看到这种行为。在您第一次加载页面之后,在刷新之前,您是否清空了控制台?有没有可能您正在查看旧的控制台输出(我知道有些浏览器喜欢保留以前页面的控制台输出)?
我不会指望这两个事件在刷新时会被触发两次,所以我的猜想是因为手动刷新或者可能Chrome 14存在与其开发控制台相关的bug而导致的陈旧的控制台输出。

我刚刚进行了一个额外的测试,以排除控制台输出理解上的错误。我创建了一个随机数并将其包含在输出中,测试明确显示前4个输出是页面最初加载时产生的,然后就在页面重新加载之前(当我释放刷新按钮)。因此,在重新加载页面后离开页面时会调用这些方法。 - Sten

2
据我所知,单击一个#xxx链接(或者链接到同一页,带或不带#xxx)不会触发window.loaddocument.ready事件。
如果您想让链接触发事件,请执行以下操作:
$('a#xxx').click(function(){
    //Your code here
}

其中xxx是链接的ID。

如果该链接用于重新加载页面,请使用

window.location.reload()

在点击事件处理程序中。


我不希望发生额外的调用。额外的调用是问题所在,我添加的链接只是为了查看是否在链接点击时发生错误调用。(它们没有) - Sten

2
似乎是Chrome/Webkit开发者控制台的一个bug。在Ubuntu上使用Chrome 14,可以通过以下步骤重现该bug。
首先创建一个包含以下JavaScript代码的页面:
var timesLoaded = 0;

function loadHandler() {
    console.log(timesLoaded, "times loaded");
    timesLoaded++;
}   

function unloadHandler(){
    console.log("unload after ", timesLoaded, " loads");
}

$(document).ready(loadHandler);
$(window).unload(unloadHandler);
  1. 用谷歌浏览器打开页面
  2. 按F12打开控制台,查看0 "times loaded"消息
  3. 在unloadHandler函数的第一行上设置一个断点
  4. 为了看到双重消息,您应该在页面上点击某个地方(例如将焦点从控制台转移到已加载的页面)
  5. 刷新页面
  6. 您可能会再次看到0 "times loaded"消息

重要的是,您的代码不会被执行两次。只是由于某种原因,webkit开发控制台会再次显示相同的消息。为了进一步调查错误,您可以执行以下操作:

  1. 加载先前的HTML页面
  2. 再次添加卸载断点(只是为了确保页面不会实际刷新)
  3. 右键单击控制台中的第一个条目(0 "times loaded")
  4. 点击检查元素(是的,控制台只是一个html/js应用程序)
  5. 找到条目所属的元素(它应该是一个div.console-group-message元素)
  6. 右键单击该元素,然后单击断开子树修改
  7. 刷新页面(再次点击HTML页面以取消聚焦控制台窗口)
  8. 在第二个烦人的消息出现之前,调试器将显示尝试附加消息的控制台代码。

2
我已在Windows上的Chromium 14上进行了测试,未观察到此行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接