【问题标题】:How to make script execution wait until jquery is loaded如何使脚本执行等到加载jquery
【发布时间】:2011-11-21 03:03:04
【问题描述】:

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


为了回应下面的答案/cmets,我发布了一些标记。

情况...asp.net母版页和子页。

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

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

  1. 母版页标题。
  2. 子页面内容块 1(位于 母版页的头,但在母版页脚本之后 称为)。
  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>

然后在masterpage的body里面,多了一个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();
    });

});

【问题讨论】:

  • 你在用$(document).ready(function(){...});吗?
  • 如果您正在加载带有简单 &lt;script src="..."&gt; 标记的脚本,则不会发生这种情况。您使用的是 RequireJS 或 LABjs 之类的东西吗?
  • 您是在$(document).ready()$(window).load() 中运行后续脚本吗?我们可以举个例子吗?
  • @AmandaMyer 现在,忽略所有关于使用准备好的文档的建议,因为你已经在这样做了,但我敢打赌是 mimetype 导致它们不能同步加载
  • 尝试将type="text/Scripts" 更改为type="text/javascript",或者将其全部删除,不再需要,同时删除language="javascript。还不如开始尝试。

标签: javascript jquery


【解决方案1】:

用途:

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

【讨论】:

  • 这个等待直到 dom 准备好,直到 jquery 被加载。他可能有 2 个脚本文件,1 个来自 CDN(来自 google 的 jquery 和本地插件),其中 1 比另一个更早加载....如果插件的加载速度比 jquery 本身快,您的代码不能解决这个问题
  • 我不同意你@Sander 这应该可以工作,因为加载是同步的
  • 你是对的,如果它们来自不同的域,我关于它们被异步加载的假设是完全错误的!对不起
  • 如果 jquery 不可用,这将引发异常,导致它永远不会进入看起来的 else 语句。猜猜这应该是一个尝试和捕捉之类的东西。
  • @SamStoelinga:谢谢,现在应该修复了。
【解决方案2】:

我认为这不是你的问题。脚本加载默认是同步的,所以除非您使用defer 属性或通过另一个 AJAX 请求加载 jQuery 本身,否则您的问题可能更像是 404。您能否显示您的标记,如果您看到请告诉我们firebug 或 web inspector 有什么可疑的地方吗?

【讨论】:

    【解决方案3】:

    编辑

    您能否为您的脚本标签尝试正确的类型? 我看到你使用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】:

      您可以使用 defer 属性在真正结束时加载脚本。

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

      但通常以正确的顺序加载脚本应该可以解决问题,因此请务必将 jquery 包含在您自己的脚本之前

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

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

      【讨论】:

      • 只要你有一个依赖就可以了
      【解决方案5】:

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

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

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

      一个匿名函数的例子:

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

      【讨论】:

      • 这对我不起作用。在方法内部,$ 没有被定义……还不知道为什么。
      • 这是一个很好的解决方案,可以让一些自定义代码在由其他人在 Adob​​e Muse 中设计的网站中运行。
      • @gidim 它不会,因为它是一个计时器而不是一个循环。但只要用户停留在页面上,它就会一直运行。
      • 最好调查一下脚本的加载顺序。我发现如果加载 jQuery 的 script 标记有一个 defer 属性,那么尽管脚本的代码定义顺序,但它会导致问题,直到稍后才加载。
      • 如果由于某种原因无法加载库,是否存在堆栈溢出的风险?
      【解决方案6】:

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

      HEADER
      BODY ==> dynamic CONTENT/PAGE
      FOOTER
      

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

      另外,您在某处读到内联小型 Javascript 很好,所以想象一下您需要在页面中使用 jQuery,baboom,$ 未定义(.. 但 ^^)。

      我喜欢 Facebook 提供的解决方案

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

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

      window.jqReady = function() {}
      

      并在布局底部添加 jQuery 包含

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

      【讨论】:

      【解决方案7】:

      还有另一种方法,尽管 Darbio 的 defer 方法更灵活。

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

      【讨论】:

        【解决方案8】:

        你可以试试 onload 事件。它在所有脚本加载后引发:

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

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

        【讨论】:

        • 这可行,但如果您的 jquery 更改页面的外观,您可能会看到一闪而过的无样式内容
        • 您可以添加事件监听器以避免覆盖其他脚本:stackoverflow.com/a/15564394/32453FWIW'
        • @rogerdpack 同意,这是更好的解决方案。
        • 经验不足,这一直是我使用的最佳解决方案。
        【解决方案9】:

        检查一下:

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

        【讨论】:

        • 这是注册文档就绪功能的便捷解决方案,谢谢
        【解决方案10】:

        除了“等待”(通常使用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
        
            }
          });
        })();
        

        【讨论】:

        • 如果 jQuery 确实定义了一个窗口属性,这将是模糊有用的,但它似乎没有?
        • 它并没有真正设置属性,但它确实通过在全局范围内定义jQuery 变量(即window)将window.jQuery 设置为一个值。这将触发代码中定义的窗口对象的属性设置器函数。
        • 如果在执行此代码之前定义了 jQuery 属性,这将不起作用;即,如果您的延迟 jquery.js 在加载此代码之前加载。一种解决方案是将延迟的 jquery.js 放在 &lt;/body&gt; 之前而不是 &lt;/head&gt; 之前
        • @user:只需在加载 jQuery(延迟或其他方式)之前执行代码。加载它的位置无关紧要,只是我的代码片段在它之前。
        • 如果您可以保证使用它的脚本在您的文档中包含 jQuery 之前出现,这将非常有用。上述循环方法也没有任何低效率或竞争情况。
        【解决方案11】:

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

        var waitForJQuery = setInterval(function () {
            if (typeof $ != 'undefined') {
        
                // place your code here.
        
                clearInterval(waitForJQuery);
            }
        }, 10);
        

        【讨论】:

        • 天才解决方案。谢谢
        • 通过演示是否可以将其编写为匿名函数,您将获得奖励积分。
        • 这个优雅的解决方案也适用于除 jquery 之外的其他 javascript 加载情况。谢谢你分享这个!
        【解决方案12】:

        我不太喜欢间隔的东西。当我想推迟 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】:

          我发现建议的解决方案仅在考虑异步代码时才有效。以下是在这两种情况下都可以使用的版本:

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

          【讨论】:

          • 谢谢,在加载时检查一次,并且仅作为后备开始每 50 毫秒循环一次,这比让它像投票最多的答案那样使用 setInterval 循环要好得多。在最好的情况下,您有 0 毫秒的延迟,而不是最佳答案的 25 毫秒的平均情况。
          • 漂亮而优雅——我喜欢你传递load 函数但又在setTimeout 中重用它的方式。
          • 有什么办法可以消除使用“load”并将其写成匿名函数?
          【解决方案14】:

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

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

          在您的setTimeoutsetInterval 中,一切都应该正常工作。

          【讨论】:

            【解决方案15】:

            让我们从 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')});
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-07-08
              • 1970-01-01
              • 1970-01-01
              • 2022-01-01
              • 2023-04-09
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多