如何使脚本执行等到加载jquery

时间:2011-09-20 13:53:25

标签: javascript jquery

我遇到的问题是页面加载速度如此之快,以至于jquery在后续脚本调用之前尚未完成加载。有没有办法检查jquery的存在,如果它不存在,请稍等片刻,然后再试一次?


在回答下面的答案/评论时,我发布了一些标记。

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

在母版页中,我引用了jquery。 然后在内容页面中,我引用了特定于页面的脚本。 当加载特定于页面的脚本时,它会抱怨“$ is undefined”。

我在标记的几个点放置警报,以查看触发事件的顺序,并确认它按此顺序触发:

  1. 母版页标题。
  2. 子页面内容块1(位于 主页的头部,但是在母版脚本之后 所谓的)。
  3. 子页面内容块2.
  4. 以下是母版页顶部的标记:

    <%@ 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();
        });
    
    });
    

15 个答案:

答案 0 :(得分:181)

派对晚了,类似于Briguy37的问题,但为了将来的参考,我使用以下方法并传入我想要推迟的函数,直到加载jQuery:

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

它会每50毫秒递归调用一次延迟方法,直到window.jQuery存在,此时它会退出并调用method()

匿名函数的示例:

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

答案 1 :(得分:18)

您可以使用defer属性在最后加载脚本。

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

但通常以正确的顺序加载脚本应该可以解决问题,所以一定要在自己的脚本之前加入jquery

如果您的代码在页面中而不在单独的js文件中,那么您必须在文档准备就绪后执行脚本,并且像这样封装代码也应该有效:

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

答案 2 :(得分:14)

另一种方法是这样做,尽管Darbio的推迟方法更灵活。

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

答案 3 :(得分:11)

修改

您可以为脚本代码尝试正确的类型吗? 我看到你使用text/Scripts,这不是javascript的正确mimetype。

使用此:

<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>

结束修改

或者您可以查看require.js,它是您的javascript代码的加载程序。

取决于您的项目,但这可能有点矫枉过正

答案 4 :(得分:11)

您可以尝试onload事件。它在加载所有脚本时引发:

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

但请记住,您可以覆盖window.onload使用的其他脚本。

答案 5 :(得分:9)

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

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

        // place your code here.

        clearInterval(waitForJQuery);
    }
}, 10);

答案 6 :(得分:5)

这是一个常见的问题,想象一下你使用了很酷的PHP模板引擎,所以你有了基础布局:

HEADER
BODY ==> dynamic CONTENT/PAGE
FOOTER

当然,你在某个地方读到最好在页面底部加载Javascript,所以你的动态内容不知道谁是jQuery(或$)。

另外你在某处阅读内联小Javascript很好,所以想象你需要在页面中使用jQuery,baboom,$未定义(..还是^^)。

我喜欢Facebook提供的解决方案

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

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

window.jqReady = function() {}

在jQuery include

之后添加到布局的底部
if (window.hasOwnProperty('jqReady')) $(function() {window.jqReady();});

答案 7 :(得分:5)

而不是“等待”(通常使用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

    }
  });
})();

答案 8 :(得分:4)

使用:

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

有关详细信息,请查看此信息:http://www.learningjquery.com/2006/09/introducing-document-ready

注意:只要您的JQuery库的脚本导入高于此调用,这就应该有效。

更新:

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

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();

答案 9 :(得分:4)

我发现建议的解决方案仅适用于处理异步代码。以下是适用于任何一种情况的版本:

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

答案 10 :(得分:2)

我认为这不是你的问题。默认情况下,脚本加载是同步的,所以除非您使用defer属性或通过另一个AJAX请求加载jQuery本身,否则您的问题可能更像404.您能否显示标记,并告诉我们是否你在萤火虫或网络检查员看到任何可疑的东西吗?

答案 11 :(得分:1)

检查一下:

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);

答案 12 :(得分:1)

我不是非常喜欢间隔的东西。当我想推迟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]();}});

答案 13 :(得分:1)

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

defer()

然后运行哪个:

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

答案 14 :(得分:0)

有关此处使用“ setTimeoutsetInterval进行加载的方法的切记。在这些情况下,有可能当您再次执行检查时,DOM已被加载,并且浏览器的DOMContentLoaded事件将被触发,因此您无法使用这些方法可靠地检测到该事件。我发现,尽管如此,jQuery的ready仍然有效,因此您可以嵌入常用的

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

在您的setTimeoutsetInterval内,一切应该正常进行。