可以推迟 jQuery 的加载吗?

IT技术 javascript jquery pagespeed
2021-02-15 23:16:07

让我们面对现实吧,jQuery/jQuery-ui 下载量很大。

Google 建议延迟加载 JavaScript以加速初始渲染。我的页面使用 jQuery 来设置一些位于页面较低位置的选项卡(大部分在初始视图之外),我想将 jQuery 推迟到页面呈现后。

Google 的延迟代码在页面加载后通过挂钩主体 onLoad 事件向 DOM 添加一个标记:

<script type="text/javascript">

 // Add a script element as a child of the body
 function downloadJSAtOnload() {
 var element = document.createElement("script");
 element.src = "deferredfunctions.js";
 document.body.appendChild(element);
 }

 // Check for browser support of event handling capability
 if (window.addEventListener)
 window.addEventListener("load", downloadJSAtOnload, false);
 else if (window.attachEvent)
 window.attachEvent("onload", downloadJSAtOnload);
 else window.onload = downloadJSAtOnload;

</script>

我想以这种方式推迟 jQuery 的加载,但是当我尝试它时,我的 jQuery 代码未能找到 jQuery(这对我来说并不完全出乎意料):

$(document).ready(function() {
    $("#tabs").tabs();
});

所以,似乎我需要找到一种方法来推迟我的 jQuery 代码的执行,直到 jQuery 被加载。如何检测添加的标签是否已完成加载和解析?

作为推论,异步加载似乎也包含一个答案。

有什么想法吗?

6个回答

试试这个,这是我不久前从 jQuerify 书签中编辑的内容。我经常使用它来加载 jQuery 并在加载后执行内容。您当然可以将那里的 url 替换为您自己的自定义 jquery 的 url。

(function() {
      function getScript(url,success){
        var script=document.createElement('script');
        script.src=url;
        var head=document.getElementsByTagName('head')[0],
            done=false;
        script.onload=script.onreadystatechange = function(){
          if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
            done=true;
            success();
            script.onload = script.onreadystatechange = null;
            head.removeChild(script);
          }
        };
        head.appendChild(script);
      }
        getScript('http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js',function(){
            // YOUR CODE GOES HERE AND IS EXECUTED AFTER JQUERY LOADS
        });
    })();

我真的会将 jQuery 和 jQuery-UI 合并到一个文件中,并使用一个 url 来访问它。如果您真的想单独加载它们,只需链接 getScripts:

getScript('http://myurltojquery.js',function(){
        getScript('http://myurltojqueryUI.js',function(){
              //your tab code here
        })
});
我已经成功地使用了它。我还将success();第 10 行的if(success && getClass.call(success) == '[object Function]') { success(); }. 只有当它不为空并且它是一个函数时,才会执行成功函数。这允许您在getScript("myScript.js")没有函数调用的情况下进行调用。
2021-04-15 23:16:07
实际上,这与 tylermwashburn 的建议完全不同。这对你来说是加载 jQuery,然后加载 jQuery ui,然后执行你的 jquery/jqueryUI 相关代码,这就是你所要求的......这段代码是跨浏览器的(这就是为什么它看起来很“花哨”)和每次都对我有用。至于 DOMready 代码,我刚刚意识到它可能有点旧,我不会使用它。我想我在某处有一个更新的 domready ......让我找到它。
2021-04-26 23:16:07
泰勒的建议很好。我要做的是使链接的 getscripts 成为主体加载事件的回调
2021-04-29 23:16:07
看起来像是 tylermwashburn 建议的花哨版本。通过推迟一切,我认为它设置了一个依赖顺序问题:MyCode 依赖于 JQueryUI 依赖于 JQuery。因此,需要一些代码以正确的顺序加载每个。你给了我一些想法。
2021-05-11 23:16:07
@Geniusknight 是的,它是 getScript()!:) 它可用于延迟多个,如果有依赖项,您需要为它们编写代码以确保在尝试运行依赖于它的任何子脚本之前加载它们。使用多维数组将是一种相当简单的方法。
2021-05-11 23:16:07

由于这是一个重要主题的排名靠前的问题,让我大胆地根据@valmarv 和@amparsand 的先前回答提供我自己的看法。

我正在使用多维数组来加载脚本。将它们之间没有依赖关系的那些组合在一起:

var dfLoadStatus = 0;
var dfLoadFiles = [
      ["http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"],
      ["http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js",
       "/js/somespecial.js",
       "/js/feedback-widget.js#2312195",
       "/js/nohover.js"]
     ];

function downloadJSAtOnload() {
    if (!dfLoadFiles.length) return;

    var dfGroup = dfLoadFiles.shift();
    dfLoadStatus = 0;

    for(var i = 0; i<dfGroup.length; i++) {
        dfLoadStatus++;
        var element = document.createElement('script');
        element.src = dfGroup[i];
        element.onload = element.onreadystatechange = function() {
        if ( ! this.readyState || 
               this.readyState == 'complete') {
            dfLoadStatus--;
            if (dfLoadStatus==0) downloadJSAtOnload();
        }
    };
    document.body.appendChild(element);
  }

}

if (window.addEventListener)
    window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
    window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;

它在加载后首先加载 jquery,然后继续立即加载其他脚本。您可以通过添加到页面上任意位置的数组来轻松添加脚本:

dfLoadFiles.push(["/js/loadbeforeA.js"]);
dfLoadFiles.push(["/js/javascriptA.js", "/js/javascriptB.js"]);
dfLoadFiles.push(["/js/loadafterB.js"]);
这对于 <script> 标签上的 async 和/或 defer 属性是否仍然必要?mediaevent.de/javascript/programm-struktur.html(抱歉这是德语,你可以用deepl.com翻译)
2021-04-30 23:16:07

这里很好地描述了异步/延迟 javascript 加载现代方法但它不适用于内联脚本

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script>
<script type="text/javascript" defer>
    $(function () {   //  <- jquery is not yet initialized
      ...
    });
</script>

@nilskp 建议了最简单的异步加载解决方案 - externalize 脚本:

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script>
<script type="text/javascript" src="resources/js/onload.js" defer></script>
element.addEventListener("load", function () {
    $('#tabs').tabs()
}, false);

试试那个。

是的!你明白了!所以,我认为这个和“&符号”答案的某种组合将是最终的解决方案。看来我需要链式加载 jQuery,然后是 jQuery-UI,然后是依赖这两者的页面代码。
2021-04-18 23:16:07
IE<9 不支持 addEventListener :(
2021-05-11 23:16:07

我在 async/defered jquery 脚本标签之后添加了这段代码,它定义了一个临时函数 $,它将累积所有加载完成后需要运行的任何内容,然后一旦我们完成,此时使用 $将被覆盖以执行功能。有了这段代码,就无需在文档中进一步更改 jQuery onload 语法。

<script defer async src="https://code.jquery.com/jquery-2.2.0.min.js">
<script>
    var executeLater = [];
    function $(func) {
        executeLater.push(func);
    }
    window.addEventListener('load', function () {
        $(function () {
            for (var c = 0; c < executeLater.length; c++) {
                executeLater[c]();
            }
        });
    })
</script>

....接着...

<script>
    $(function() {
        alert("loaded");
    });
</script>
工作完美只是添加了两者defer async谢谢
2021-05-09 23:16:07