jQuery $(document).ready() 被触发两次。

76

我在网上搜索了很久,试图找出这里发生了什么事情,但是我没有得到一个确切的答案。

在我的网站上有一个$(document).ready,无论里面的代码是什么,它都会运行多次。

我已经阅读了关于jQuery的bug报告,了解到如果语句内部出现异常,.ready事件将被触发两次。然而,即使我有以下代码,它仍然运行两次:

$(document).ready(function() {
    try{    
        console.log('ready');
        }
    catch(e){
        console.log(e);
    }
});

在控制台中,我只看到“ready”被记录两次。是否可能另一个具有异常的.ready会引起问题?我的理解是所有.ready标记彼此独立,但我似乎找不到这个问题的根源所在?

以下是该网站的head块:

<head>
<title>${path.title}</title>
<meta name="Description" content="${path.description}" />
<link href="${cssHost}${path.pathCss}" rel="stylesheet" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="media/js/fancybox/jquery.fancybox.pack.js" type="text/javascript" ><!-- --></script>
<script src="/media/es/jobsite/js/landing.js" type="text/javascript" ><!-- --></script>
<script src="/media/es/jobsite/js/functions.js" type="text/javascript"><!-- -->    </script>
<script src="/media/es/jobsite/js/jobParsing.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="/media/es/jobsite/js/queryNormilization.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="${jsHost}/js/jquery/jquery.metadata.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="${jsHost}/js/jquery/jquery.form.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="http://ajax.aspnetcdn.com/ajax/jquery.validate/1.7/jquery.validate.min.js" type="text/javascript" charset="utf-8"><!----></script>
<script src="${jsHost}/js/jquery.i18n.properties-min.js" type="text/javascript" charset="utf-8"><!----></script>

<script type="text/javascript" charset="utf-8">

function updateBannerLink() {
    var s4 = location.hash.substring(1);
    $("#banner").attr('href','http://INTELATRACKING.ORG/?a=12240&amp;c=29258&amp;s4='+s4+'&amp;s5=^');
}

</script>
</head>

不用管 JSP 变量,但是你可以看到我只调用了 functions.js 文件一次(其中包含.ready 函数)。


2
有什么东西会导致页面刷新或第二次加载 - 像Firebug这样的调试工具还是其他什么东西? - Dylan Beattie
1
它只记录了一次对我来说 - Elliot Bonneville
你能提供一下你正在使用的jQuery版本以及出现问题的浏览器吗? - Victor
1
我猜测同样的代码被嵌入了两次。DOM准备就绪事件在DOM准备就绪时触发一次,ready处理程序只是绑定到该事件。如果绑定了两次,则会执行两次。也许您应该检查所有的JavaScript,看看这段代码是否在其他地方重复出现,或者您可能只是在某个其他处理程序中留下了一个控制台日志,而某些其他代码正在执行,但您只是留下了一个控制台日志。 - Alok Swain
这不是控制台日志留在某个地方的问题,而是这个特定的代码块运行了两次,我也没有看到任何可能调用页面刷新或页面加载的地方。这在除IE之外的所有浏览器中都会发生。 - Xenology
显示剩余2条评论
14个回答

71

ready事件不会触发两次。更有可能的情况是,您的代码正在移动或操作包含代码的元素,这会导致浏览器重新执行脚本块。

将脚本标签放在中或在结束标签之前,而不要使用$('body').wrapInner();来避免这种情况。使用$('body').html($('body').html().replace(...));能达到同样的效果。


1
有一些 JavaScript 库(如 KendoUI)会导致 document.ready 函数在单个页面上执行多次。这并非不可能。 - qJake
12
这里的问题出在页面中包含了一个IFRAME标签。当移除该标签后,document.ready事件只被触发一次。可以看到此标签导致页面重新加载的明显原因。 <iframe id="pathIframe" frameborder="0" height="600" width="100%" name="path" scrolling="auto" src="#"></iframe> - Xenology
1
是的,我不知道为什么在IE中没有发生这种情况,虽然这个答案并不完全正确,但它让我尝试查找页面是否以某种方式操纵BODY使其加载两次,因此它让我走上了解决问题的正确道路。 - Xenology
9
避免使用 src="#" 属性,因为它会在父窗口和 iframe 内加载同一页,导致代码看起来被调用了两次。删除 src 属性或将其设置为 "about:blank" 可以避免这种行为。 - Inferpse
@guest271314它可以被多次执行,每次都会运行回调函数,但事件本身只发生一次。它不能再次触发,导致回调再次发生,这就是这个答案的重点所在。 - Kevin B
显示剩余8条评论

43

我也遇到过这种情况,但后来我发现由于错误的合并导致脚本被包含了两次。


在asp.net mvc中,我错过了一个包含文件夹中所有js的捆绑包,并为单个文件创建了一个额外的捆绑包,导致同一文件被包含了两次。 - Darion Badlydone
我在Laravel布局和动态页面中都包含了相同的脚本。 将动态php文件中的包含删除解决了我的问题。 - Prasanna Kumar
谢谢你提到这个。虽然很明显,但是你的回答让我再次检查了我的包含文件,解决了问题 ;) - florieger
是的,我遇到了同样的问题,不小心重复包含了相同的脚本。 - RKM

39

在使用KendoUI时我遇到了这个问题...调用弹出窗口会导致document.ready事件多次触发。简单的解决方案是设置全局标志,以便它只运行一次:

这在使用KendoUI时发生了...调用弹出窗口会导致document.ready事件触发多次。简单的解决方法是设置一个全局标志,确保它只运行一次:

var pageInitialized = false;
$(function()
{
    if(pageInitialized) return;
    pageInitialized = true;
    // Put your init logic here.
});

这有点取巧,但它能用。


18

确保不要重复包含JS文件。这就是我的情况。


好的,很棒!我从另一个主脚本中使用$.getScript调用了我的脚本。但是我忘记了添加一个<script>标签进行调试! - Jeff
该死!这也发生在我身上了。悲伤但却是真的。 - Magno C

3
您可以考虑使用

。该标签在IT技术中比较常见,用于定义段落。

window.onload

代替
$(document).ready

1
只想说这对我很有用。在使用谷歌地图时,我的东西似乎触发了两次,但是使用window.onload而不是document.ready对我很有效,所以谢谢。 - balslev

3

尝试将以下代码放入您的functions.js中,以防止其被执行两次:

var checkit = window.check_var;
if(checkit === undefined){ //file never entered. the global var was not set.
    window.check_var = 1;
}
else {
    //your functions.js content 
}

然而,我建议您进一步了解它,以查看您第二次调用的位置。

我想避免这样的事情,因为它很混乱,而且我不喜欢把这个功能拼凑在一起的想法。虽然如果我无法解决这个问题,这可能是我唯一的解决方案。 - Xenology
只是想在这里补充一下,尽管这样做很投机取巧,但也是不正确的。语法应该改为 "if (typeof checkit === 'undefined')." typeof 总是返回一个字符串。 - Zach Pedigo

1
当我尝试刷新部分页面时,遇到了类似的问题。我调用了一个返回ActionResult而不是返回PartialViewResult的方法。这个ActionResult导致我的ready()函数运行了两次。

1
我今天遇到了类似的问题。在我的情况下,<button type="submit"> 导致 $(document).ready(...) 事件再次触发。将代码更改为<button type="button"> 解决了我的问题。
请参见此处的 stackoverflow 获取更多详细信息。

1

当您在html中两次添加相同的控制器时,可能会遇到此问题。例如:
[js]

app.controller('AppCtrl', function ($scope) {
 $(document).ready(function () {
        alert("Hello");
        //this will call twice 
    });
});

[html]

//controller mentioned for the first time
<md-content ng-controller="AppCtrl">
    //some thing
</md-content>

//same controller mentioned again 
<md-content ng-controller="AppCtrl">
    //some thing
</md-content>

0
如果iframe没有显示任何内容,并且用于其他目的(例如在不重新加载页面的情况下上传文件),您可以像这样做:
<iframe id="upload_target" name="upload_target" style="width:0;height:0;border:0px solid #fff;"></iframe>

请注意,src未包含在内,这会防止在文档上触发第二个"on ready"事件。

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