How to make script execution wait until jquery is loaded

我遇到了一个问题,页面加载得太快,以至于 jquery 在被后续脚本调用之前还没有完成加载。有没有一种方法可以检查 jquery 是否存在,如果它不存在,请稍等片刻,然后再试一次?


作为对以下回答/评论的回应,我发布了一些标记。

情况... asp.net 主页和子页。

在母版页中,我有一个对 jquery 的引用。 然后在内容页面中,我有一个对页面特定脚本的引用。 当加载特定于页面的脚本时,它会抱怨“ $是未定义的”。

我在标记中的几个点处设置了警报,以查看事件发生的顺序,并确认它的发生顺序如下:

  1. Master page header.
  2. Child page content block 1 (located inside the 但是在母版脚本之后 电话)。
  3. 子页面内容块2。

以下是母版页面顶部的标记:

<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="SiteMaster" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Reporting Portal</title>
<link href="~/Styles/site.css" rel="stylesheet" type="text/css" />
<link href="~/Styles/red/red.css" rel="stylesheet" type="text/css" />
<script type="text/Scripts" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/Scripts" language="javascript" src="../Scripts/jquery.dropdownPlain.js"></script>
<script type="text/Scripts" language="javascript" src="../Scripts/facebox.js"></script>
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
<asp:ContentPlaceHolder ID="head" runat="server">
</asp:ContentPlaceHolder>
</head>

然后,在母版页的正文中,还有一个额外的 ContentPlaceHolder:

 <asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>

在子页面中,看起来是这样的:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Dashboard.aspx.cs" Inherits="Data.Dashboard" %>
<%@ Register src="../userControls/ucDropdownMenu.ascx" tagname="ucDropdownMenu" tagprefix="uc1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
<link rel="stylesheet" type="text/css" href="../Styles/paserMap.css" />
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
***CONTENT HERE***
<script src="../Scripts/Dashboard.js" type="text/javascript"></script>
</asp:Content>

下面是“ . ./Script/Dashboard.js”文件的内容:

    $(document).ready(function () {


$('.tgl:first').show(); // Show the first div


//Description: East panel parent tab navigation
$('.tabNav label').click(function () {
$('.tabNav li').removeClass('active')
$(this).parent().addClass('active');


var index = $(this).parent('li').index();
var divToggle = $('.ui-layout-content').children('div.tgl');


//hide all subToggle divs
divToggle.hide();
divToggle.eq(index).show();
});


});
165818 次浏览

用途:

$(document).ready(function() {
// put all your jQuery goodness in here.
});

查看更多信息: http://www.learningjquery.com/2006/09/introducing-document-ready

Note: This should work as long as the script import for your JQuery library is above this call.

更新:

如果由于某种原因您的代码没有同步加载(我从来没有遇到过,但显然可能从下面的评论不应该发生这种情况) ,您可以像下面这样编写代码。

function yourFunctionToRun(){
//Your JQuery goodness here
}


function runYourFunctionWhenJQueryIsLoaded() {
if (window.$){
//possibly some other JQuery checks to make sure that everything is loaded here


yourFunctionToRun();
} else {
setTimeout(runYourFunctionWhenJQueryIsLoaded, 50);
}
}


runYourFunctionWhenJQueryIsLoaded();

我觉得这不是你的问题。默认情况下,脚本加载是同步的,所以除非您使用 defer属性或通过另一个 AJAX 请求加载 jQuery 本身,否则您的问题可能更像是404。您可以显示您的标记,并让我们知道,如果您看到任何可疑的防火或网络检查?

edit

Could you try the correct type for your script tags? 我看到你使用的是 text/Scripts,这对 javascript 来说并不是正确的摹型。

用这个:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript" src="../Scripts/jquery.dropdownPlain.js"></script>
<script type="text/javascript" src="../Scripts/facebox.js"></script>

结束编辑

或者你可以看看 需求,它是你的 javascript 代码的加载程序。

depending on your project, this could however be a bit overkill

您可以使用 defer 属性在真正的末尾加载脚本。

<script type='text/javascript' src='myscript.js' defer='defer'></script>

但是正常情况下,按照正确的顺序加载脚本应该可以做到这一点,所以一定要把 jquery 包含放在自己的脚本之前

如果您的代码在页面中,而不是在一个单独的 js 文件中,那么您必须在文档准备好之后才能执行脚本,并且像这样封装您的代码也应该可以工作:

$(function(){
//here goes your code
});

这与 Briguy37的问题很相似,但是为了以后的参考,我使用以下方法并传入我想推迟到 jQuery 加载完成的函数:

function defer(method) {
if (window.jQuery) {
method();
} else {
setTimeout(function() { defer(method) }, 50);
}
}

它将每隔50毫秒递归地调用 Defer 方法,直到 window.jQuery存在时它退出并调用 method()

具有匿名函数的示例:

defer(function () {
alert("jQuery is now loaded");
});

这是一个常见的问题,假设您使用了一个很酷的 PHP 模板引擎,那么您就有了自己的基本布局:

HEADER
BODY ==> dynamic CONTENT/PAGE
FOOTER

当然,在某些地方读到最好在页面底部加载 Javascript,这样动态内容就不知道谁是 jQuery (或 $)。

Also you read somewhere it's good to inline small Javascript, so imagine you need jQuery in a page, baboom, $ is not defined (.. yet ^^).

我喜欢 Facebook 提供的解决方案

window.fbAsyncInit = function() { alert('FB is ready !'); }

因此,作为一个懒惰的程序员(我应该说是一个优秀的程序员 ^ ^) ,你可以使用一个等价物(在你的页面中) :

window.jqReady = function() {}

And add at the bottom of your layout, after jQuery include

if (window.hasOwnProperty('jqReady')) $(function() {window.jqReady();});

Yet another way to do this, although Darbio's defer method is more flexible.

(function() {
var nTimer = setInterval(function() {
if (window.jQuery) {
// Do something with jQuery
clearInterval(nTimer);
}
}, 100);
})();

您可以尝试 onload 事件。当所有脚本都已加载时,该事件将引发:

window.onload = function () {
//jquery ready for use here
}

But keep in mind, that you may override others scripts where window.onload using.

看看这个:

https://jsfiddle.net/neohunter/ey2pqt5z/

它将创建一个假的 jQuery 对象,允许您使用 jQuery 的 onload 方法,它们将在加载 jQuery 时立即执行。

并不完美。

// This have to be on <HEAD> preferibly inline
var delayed_jquery = [];
jQuery = function() {
if (typeof arguments[0] == "function") {
jQuery(document).ready(arguments[0]);
} else {
return {
ready: function(fn) {
console.log("registering function");
delayed_jquery.push(fn);
}
}
}
};
$ = jQuery;
var waitForLoad = function() {
if (typeof jQuery.fn != "undefined") {
console.log("jquery loaded!!!");
for (k in delayed_jquery) {
delayed_jquery[k]();
}
} else {
console.log("jquery not loaded..");
window.setTimeout(waitForLoad, 500);
}
};
window.setTimeout(waitForLoad, 500);
// end






// now lets use jQuery (the fake version)
jQuery(document).ready(function() {
alert('Jquery now exists!');
});


jQuery(function() {
alert('Jquery now exists, this is using an alternative call');
})


// And lets load the real jquery after 3 seconds..
window.setTimeout(function() {
var newscript = document.createElement('script');
newscript.type = 'text/javascript';
newscript.async = true;
newscript.src = 'https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(newscript);
}, 3000);

与“等待”(通常使用 setTimeout完成)不同,您还可以使用窗口本身中 jQuery 对象的定义作为一个钩子来执行依赖于它的代码。这可以通过使用 Object.defineProperty定义的属性定义来实现。

(function(){
var _jQuery;
Object.defineProperty(window, 'jQuery', {
get: function() { return _jQuery; },
set: function($) {
_jQuery = $;


// put code or call to function that uses jQuery here


}
});
})();

最简单和最安全的方法是使用这样的东西:

var waitForJQuery = setInterval(function () {
if (typeof $ != 'undefined') {


// place your code here.


clearInterval(waitForJQuery);
}
}, 10);

我不太喜欢间隔音。当我想要延迟 jquery 或者其他任何东西时,它通常是这样的。

首先:

<html>
<head>
<script>var $d=[];var $=(n)=>{$d.push(n)}</script>
</head>

然后:

 <body>
<div id="thediv"></div>


<script>
$(function(){
$('#thediv').html('thecode');
});
</script>


<script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>

最后:

  <script>for(var f in $d){$d[f]();}</script>
</body>
<html>

或者不那么令人难以置信的版本:

<script>var def=[];function defer(n){def.push(n)}</script>
<script>
defer(function(){
$('#thediv').html('thecode');
});
</script>
<script src="http://code.jquery.com/jquery-3.2.1.min.js" type="text/javascript"></script>
<script>for(var f in def){def[f]();}</script>

在异步的情况下,您可以在 jquery onload 上执行推送函数。

<script async onload="for(var f in def){def[f]();}"
src="jquery.min.js" type="text/javascript"></script>

或者:

function loadscript(src, callback){
var script = document.createElement('script');
script.src = src
script.async = true;
script.onload = callback;
document.body.appendChild(script);
};
loadscript("jquery.min", function(){for(var f in def){def[f]();}});

I have found that suggested solution only works while minding asynchronous code. Here is the version that would work in either case:

document.addEventListener('DOMContentLoaded', function load() {
if (!window.jQuery) return setTimeout(load, 50);
//your synchronous or asynchronous jQuery-related code
}, false);

关于这里加载使用 setTimeoutsetInterval的方法的一个附带说明。在这些情况下,当您的检查再次运行时,DOM 可能已经加载,并且浏览器的 DOMContentLoaded事件已经触发,因此您无法使用这些方法可靠地检测到该事件。但是我发现 jQuery 的 ready仍然可以工作,所以您可以嵌入您通常使用的

JQuery (document) . ready (function ($){ ... }

在你的 setTimeoutsetInterval和一切应该正常工作。

让我们从 Dario 扩展 defer(),使其更具可重用性。

function defer(toWaitFor, method) {
if (window[toWaitFor]) {
method();
} else {
setTimeout(function () { defer(toWaitFor, method) }, 50);
}
}

然后运行:

function waitFor() {
defer('jQuery', () => {console.log('jq done')});
defer('utag', () => {console.log('utag done')});
}