javascript 在加载 jQuery 之前处理依赖于 jQuery 的代码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8298430/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 02:58:07  来源:igfitidea点击:

Handling code which relies on jQuery before jQuery is loaded

javascriptjquery

提问by Jordan Reiter

I'd like to follow the general guideline of putting all JavaScript at the very bottom of the page, to speed up loading time and also to take care of some pesky issues with conflicting jQuery versions in a web app (Django).

我想遵循将所有 JavaScript 放在页面最底部的一般准则,以加快加载时间并处理 Web 应用程序 (Django) 中冲突 jQuery 版本的一些麻烦问题。

However, every so often I have some code, code which depends on jQuery, but which must be further up on the page (basically the code can't be moved to the bottom).

然而,每隔一段时间我就会有一些代码,这些代码依赖于 jQuery,但必须在页面的更上方(基本上代码不能移到底部)。

I'm wondering if there's an easy way to code this so that even though jQuery is not yet defined the code works when jQuery is defined.

我想知道是否有一种简单的方法来对此进行编码,以便即使尚未定义 jQuery,但在定义 jQuery 时代码也能工作。

The following seems, I have to say, like overkill but I don't know of another way to do it:

我不得不说,以下似乎有点矫枉过正,但我​​不知道还有其他方法可以做到:

function run_my_code($) {
    // jquery-dependent code here
    $("#foo").data('bar', true);
}
var t = null;
function jquery_ready() {
    if (window.jQuery && window.jQuery.ui) {
        run_my_code(window.jQuery);
    } else {
        t = window.setTimeout(jquery_ready, 100);
    }
}
t = window.setTimeout(jquery_ready, 100);

Actually, I might need to use code more than once in a page, code that doesn't know about other code, so even this probably won't work unless I rename each jquery_ready to something like jquery_ready_guid, jquery_ready_otherguidand so on.

实际上,我可能需要在一个页面中多次使用代码,这些代码不知道其他代码,所以即使我将每个 jquery_ready 重命名为 jquery_ready_ guid、 jquery_ready_ otherguid等,否则即使这样也可能不起作用。

Clarification

澄清

Just so this is clear, I am putting the include to JavaScript (<script type="text/javascript" src="jquery.min.js" />) at the very bottomof the page, just before the </body>. So I can't use the $.

为了清楚起见,我将包含到 JavaScript ( <script type="text/javascript" src="jquery.min.js" />) 放在页面的最底部,就在</body>. 所以我不能使用$.

采纳答案by Rich O'Kelly

Your way is the only way that I know of, though I would ensure that the scoping is a little tighter:

你的方式是我所知道的唯一方式,但我会确保范围更严格:

(function() {
  var runMyCode = function($) {
    // jquery-dependent code here
    $("#foo").data('bar', true);
  };

  var timer = function() {
    if (window.jQuery && window.jQuery.ui) {
      runMyCode(window.jQuery);
    } else {
      window.setTimeout(timer, 100);
    }
  };
  timer();
})();

Update

更新

Here's a little deferred loader I cobbled together:

这是我拼凑的一个小延迟加载器:

var Namespace = Namespace || { };
Namespace.Deferred = function () {
  var functions = [];
  var timer = function() {
    if (window.jQuery && window.jQuery.ui) {
        while (functions.length) {
            functions.shift()(window.jQuery);
        }
    } else {
        window.setTimeout(timer, 250);
    }
  };
  timer();
  return {
    execute: function(onJQueryReady) {
        if (window.jQuery && window.jQuery.ui) {
            onJQueryReady(window.jQuery);
        } else {
            functions.push(onJQueryReady);
        }
    }
  };
}();

Which would then be useable like so:

然后可以像这样使用:

Namespace.Deferred.execute(runMyCode);

回答by bodolsog

Simple use pure javascript version of $(document).ready();:

简单使用纯 javascript 版本$(document).ready();

document.addEventListener("DOMContentLoaded", function(event) { 
    //you can use jQuery there
});

回答by Ashkan Mobayen Khiabani

The best way I have found is to write the code in a function and call the function after jquery is loaded:

我发现的最好方法是在函数中编写代码并在加载 jquery 后调用该函数:

function RunAfterjQ(){
// Codes that uses jQuery
}

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
    RunAfterjQ();
</script>

Update:For master pages, you can define an array to push functions in the head of the master page:

更新:对于母版页,您可以定义一个数组来在母版页的头部推送函数:

var afterJQ = [];

then at the bottom of master page run all the functions pushed in to this array:

然后在母版页的底部运行推送到此数组的所有函数:

<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
    for(var i = 0; i < afterJQ.length; i++) afterJQ[i]();
</script>

Everywhere that you need to use javascript that relies on jQuery and is before jQuery is defined just push it in to this array:

在任何需要使用依赖于 jQuery 的 javascript 并且在 jQuery 被定义之前的地方,只需将它推入这个数组:

afterJQ.push( function() { 
    // this code will execute after jQuery is loaded.
 });

回答by radiaph

Here is a way to write injected code that will be run only after jQuery loads (whether synchronously or asynchronously).

这是一种编写仅在 jQuery 加载(无论是同步还是异步)后运行的注入代码的方法。

<script>
if ( ! window.deferAfterjQueryLoaded ) {
    window.deferAfterjQueryLoaded = [];
    Object.defineProperty(window, "$", {
        set: function(value) {
            window.setTimeout(function() {
                $.each(window.deferAfterjQueryLoaded, function(index, fn) {
                    fn();
                });
            }, 0);
            Object.defineProperty(window, "$", { value: value });
        },

        configurable: true
    });
}

window.deferAfterjQueryLoaded.push(function() {
    //... some code that needs to be run
});
</script>

What this does is:

它的作用是:

  1. Defines deferAfterjQueryLoadedlazily, so you don't need to inject that into head.
  2. Defines a setterfor window.$. When jQuery loads, one of the last things it does is assign to the global $variable. This allows you to trigger a function when that happens.
  3. Schedules the deferred functions to run as soon as possible after the jQuery script finishes (setTimeout(..., 0);).
  4. Has the setter remove itself.
  1. deferAfterjQueryLoaded懒惰地定义,因此您无需将其注入head.
  2. 定义一个二传手window.$。当 jQuery 加载时,它所做的最后一件事就是分配给全局$变量。这允许您在发生这种情况时触发功能。
  3. 安排延迟的函数在 jQuery 脚本完成后尽快运行 ( setTimeout(..., 0);)。
  4. 让二传手移除自己。

For complete cleanliness you could have the scheduled function remove deferAfterjQueryLoadedas well.

为了完全清洁,您也可以删除预定功能deferAfterjQueryLoaded

回答by Parris

How about:

怎么样:

<script>
    window.deferAfterjQueryLoaded = [];
    window.deferAfterjQueryLoaded.push(function() {
        //... some code that needs to be run
    });

    // ... further down in the page

    window.deferAfterjQueryLoaded.push(function() {
        //... some other code to run
    });
</script>

<script src="jquery.js" />
<script>
    $.each(window.deferAfterjQueryLoaded, function(index, fn) {
        fn();
    });
</script>

This works because every script here is completely blocking. Meaning the creation of the deferAfterjQueryLoadedarray and all functions being created and pushed to that array occur first. Then jQuery completely loads. Then you iterate through that array and execute each function. This works if the scripts are in separate files as well just the same way.

这是有效的,因为这里的每个脚本都是完全阻塞的。这意味着首先创建deferAfterjQueryLoaded数组以及创建并推送到该数组的所有函数。然后 jQuery 完全加载。然后遍历该数组并执行每个函数。如果脚本位于单独的文件中,这也同样有效。

If you ALSO want DOMReady to fire you can nest a $(function() {})inside of one of your deferAfterjQueryLoaded functions like such:

如果您还希望 DOMReady 触发,您可以$(function() {})在其中一个 deferAfterjQueryLoaded 函数中嵌套一个,如下所示:

window.deferAfterjQueryLoaded.push(function() {
    $(function() {
        console.log('jquery loaded and the DOM is ready');
    });
    console.log('jquery loaded');
});

Ultimately, you should really refactor your code so everything is actually down at the bottom, and have a system conducive to that model. It is much easier to understand everything occurring and more performant (especially if you have separate scripts).

最终,你应该真正重构你的代码,这样一切实际上都在底部,并有一个有利于该模型的系统。更容易理解发生的一切,而且性能更高(特别是如果您有单独的脚本)。

回答by Andrew

I have this same problem, but with a ton of files, I use headjsto manage the loading, it's only 2kb so there isn't really a problem, for me anyway, of putting in the header. Your code then becomes,

我有同样的问题,但是有大量文件,我使用headjs来管理加载,它只有 2kb,所以对于我来说,放入标题并没有真正的问题。你的代码然后变成,

head.ready(function(){
  $...
});

and at the bottom of the page,

在页面底部,

head.js('/jquery.min.js');

回答by Daniel A. White

You should be able to do this on a documentreadyevent.

您应该能够在documentready事件中执行此操作。

回答by brother Filip

function jQueryGodot(code)
{
    if (window.jQuery)
    {
        code(window.jQuery);        
    }
    else
    {
        if (!window.$)
        {
            window.$ = { codes: [] };
            window.watch('$', function(p, defered, jQuery) {
                jQuery.each(defered.codes, function(i, code) {
                    code(jQuery);
                });
                return jQuery;
            });
        }

        window.$.codes.push(code);
    }
}

jQueryGodot(function($) {
    $('div').html('Will always work!');
})

Working example on JSFiddle.

JSFiddle 上的工作示例

Code passed to jQueryGodot function will always be executed no matter if it is called before or after jQuery is loaded.

传递给 jQueryGodot 函数的代码无论是在 jQuery 加载之前还是之后调用,都将始终执行。

The solution relies on Object.watch which requires this polyfill (660 bytes minified) in most of the browsers: https://gist.github.com/adriengibrat/b0ee333dc1b058a22b66

该解决方案依赖于 Object.watch,它需要在大多数浏览器中使用这个 polyfill(660 字节缩小):https: //gist.github.com/adriengibrat/b0ee333dc1b058a22b66

回答by Viktor Tabori

You can defer all calls like jQuery(function(){...}) withoutthe loop of a setTimeout: https://jsfiddle.net/rL1f451q/3/

您可以推迟所有调用,如 jQuery(function(){...})没有setTimeout 循环:https: //jsfiddle.net/rL1f451q/3/

It is collecting every jQuery(...) call into an array until jQuery is not defined, then the second code executes them when jQuery is available.

它将每个 jQuery(...) 调用收集到一个数组中,直到未定义 jQuery,然后第二个代码在 jQuery 可用时执行它们。

Put this in the head or the beginning of the body:

把它放在头部或身体的开头:

<!-- jQuery defer code body: deferring jQuery calls until jQuery is loaded -->
<script>
  window.jQueryQ = window.jQueryQ || [];
  window.$ = window.jQuery = function(){
    window.jQueryQ.push(arguments);
  }
</script>
<!-- end: jQuery defer code body -->

And this at the very end of the body, afterthe jQuery script:

这是在正文的最后,jQuery 脚本之后:

<!-- jQuery deferring code footer: add this to the end of body and after the jQuery code -->
<script>
  jQuery(function(){
    jQuery.each(window.jQueryQ||[],function(i,a){
      // to understand why setTimeout 0 is useful, see: https://www.youtube.com/watch?v=8aGhZQkoFbQ, tldr: having a lot of calls wont freeze the website
      setTimeout(function(){
        jQuery.apply(this,a);
      },0);
    });
  });
</script>
<!-- end: jQuery deferring code footer -->

回答by Yorki

I've wrote simple js code for handle such cases: https://github.com/Yorkii/wait-for

我写了简单的 js 代码来处理这种情况:https: //github.com/Yorkii/wait-for

Then you can use it like this

然后你可以像这样使用它

waitFor('jQuery', function () {
   //jQuery is loaded
   jQuery('body').addClass('done');
});

You can even wait for multiple libraries

您甚至可以等待多个库

waitFor(['jQuery', 'MyAppClass'], function () {
   //Both libs are loaded
});