簡體   English   中英

是否可以推遲加載 jQuery?

[英]Possible to defer loading of jQuery?

讓我們面對現實吧,jQuery/jQuery-ui 下載量很大。

Google 建議延遲加載 JavaScript以加快初始渲染速度。 我的頁面使用 jQuery 設置一些位於頁面下方的選項卡(大部分不在初始視圖中),我想將 jQuery 推遲到頁面呈現后。

谷歌的延遲代碼在頁面加載后通過鈎子到正文 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 被加載。 如何檢測添加的標簽已完成加載和解析?

作為推論, 異步加載似乎也包含一個答案。

有什么想法嗎?

試試這個,這是我不久前從 jQuerify 小書簽中編輯的。 我經常使用它來加載 jQuery 並在加載后執行一些東西。 您當然可以用您自己的 url 替換 url 到您定制的 jquery。

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

由於這是一個重要主題的最高級別問題,因此讓我如此大膽地根據@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"]);

這是對異步/延遲 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:

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

我在異步/延遲 jquery 腳本標簽之后添加了這段代碼,這定義了一個臨時的 function $ 它將累積在所有內容完成加載時需要運行的任何內容,然后一旦我們完成,此時使用 $將被覆蓋以執行功能。 使用這段代碼,無需在文檔中進一步更改 jQuery 加載語法。

<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>
element.addEventListener("load", function () {
    $('#tabs').tabs()
}, false);

試試看。

在某些情況下,您可以在加載 jquery 時觸發事件。

<script type="text/javascript">
    (function (window) {

        window.jQueryHasLoaded = false;

        document.body.addEventListener('jqueryloaded', function (e) {
            console.log('jqueryloaded ' + new Date() );
        }, false);

        function appendScript(script) {
            var tagS = document.createElement("script"), 
                s = document.getElementsByTagName("script")[0];
            tagS.src = script.src;
            s.parentNode.insertBefore(tagS, s);

            if ( script.id == 'jquery' ) {
                tagS.addEventListener('load', function (e) {
                    window.jQueryHasLoaded = true;
                    var jQueryLoaded = new Event('jqueryloaded');
                    document.body.dispatchEvent(jQueryLoaded);
                }, false);
            }
        }

        var scripts = [
            {
                'id': 'jquery',
                'src': 'js/libs/jquery/jquery-2.0.3.min.js'
            },
            {
                'src': 'js/myscript1.js'
            },
            {
                'src': 'js/myscript2.js'
            }
        ];

        for (var i=0; i < scripts.length; i++) {
            appendScript(scripts[i]);
        }

    }(window));
</script>

然后將您的依賴項包裝在 function 中:

// myscript1.js 
(function(){ 

    function initMyjQueryDependency() {
        console.log('my code is executed after jquery is loaded!');
        // here my code that depends on jquery
    }

    if ( jQueryHasLoaded === true )
        initMyjQueryDependency();
    else
        document.body.addEventListener('jqueryloaded', initMyjQueryDependency, false);

}());

如果 jquery 在其他腳本之后完成加載,則在觸發 jqueryloaded 事件時將執行您的依賴項。

如果 jquery 已經加載, jQueryHasLoaded === true ,你的依賴將被執行initMyjQueryDependency()

將 jQuery 和 jQuery 相關代碼放在 HTML 文件的末尾。

編輯:更清楚一點

<html>
<head></head>
<body>
    <!-- Your normal content here -->
    <script type="text/javascript" src="http://path/to/jquery/jquery.min.js"></script>
    <script>//Put your jQuery code here</script>
</body>
</html>

這是我的版本,它支持鏈接以確保腳本一個接一個地加載,基於&的代碼:

var deferredJSFiles = ['jquery/jquery', 'file1', 'file2', 'file3'];
function downloadJSAtOnload() {
    if (!deferredJSFiles.length)
        return;
    var deferredJSFile = deferredJSFiles.shift();
    var element = document.createElement('script');
    element.src = deferredJSFile.indexOf('http') == 0 ? deferredJSFile : '/js/' + deferredJSFile + '.js';
    element.onload = element.onreadystatechange = function() {
        if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')
            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;
<!doctype html>
<html>
    <head>

    </head>
    <body>
        <p>If you click on the "Hide" button, I will disappear.</p>
        <button id="hide" >Hide</button>
        <button id="show" >Show</button>

        <script type="text/javascript">
            function loadScript(url, callback) {

                var script = document.createElement("script")
                script.type = "text/javascript";

                if (script.readyState) {  //IE
                    script.onreadystatechange = function() {
                        if (script.readyState == "loaded" ||
                                script.readyState == "complete") {
                            script.onreadystatechange = null;
                            callback();
                        }
                    };
                } else {  //Others
                    script.onload = function() {
                        callback();
                    };
                }

                script.src = url;
                document.body.appendChild(script);
            }
            loadScript("http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js",
                    function() {
                        //YAHOO.namespace("mystuff");
                        $("#show").click(function() {
                            $("p").show();
                        });
                        $("#hide").click(function() {
                            $("p").hide();
                        });

                        //more...
                    });
        </script>

    </body>
</html>

我認為 Modernizr.load() 在這里值得一提 - 它很好地處理依賴項加載

以下代碼應在 window 完成加載后加載您的腳本:

<html>
<head>
    <script>
    var jQueryLoaded = false;
    function test() {
        var myScript = document.createElement('script');
        myScript.type = 'text/javascript';
        myScript.async = true;
        myScript.src = jQueryLoaded ? 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js' : 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js';
        document.body.appendChild(myScript);

        if(!jQueryLoaded){
            alert('jquery was loaded');
            jQueryLoaded = true;
            test();
        } else {
            alert('jqueryui was loaded');   
        }
    }

    if (window.addEventListener){
        alert('window.addEventListener');
        window.addEventListener("load", test, false);
    } else if (window.attachEvent){
        alert('window.attachEvent');
        window.attachEvent("onload", test);
    } else{
        alert('window.onload');
        window.onload = test;
    }
    </script>
</head>
<body>
<p>Placeholder text goes here</p>
</body>
</html>

在 Chrome、FF 和 IE9 中為我工作 - 讓我知道這是否有幫助

Well it seems to me, all you have to do is either a) add the jQuery code you want to run on load, to the end of the jQuery file or b) append it to the downloadJSAtOnload function like so:

<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);
 $("#tabs").tabs(); // <==== NOTE THIS. This should theoretically run after the
                    // script has been appended, though you'll have to test this
                    // because I don't know if the JavaScript above will wait for
                    // the script to load before continuing
 }

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

Google Analytics 使用了一個簡單的技巧。

准備

1.在你的 HTML 的頭部添加一個小腳本

<script>
    window.jQuery_store = [];
    window.jQueryReady = function (fn) { jQuery_store.push(fn); }
</script>

function jQueryReady 只會將代表保存到數組中以備將來使用。

2.創建一個新的 JS 腳本jquery-ready.js ,包含下一個內容:

// When jQuery is finaly ready
$(function() {
    // Replace previous implementation
    window.jQueryReady = function(fn) {
        // jQuery is loaded call immediately
        fn();
    }
    
    // Call all saved callbacks
    for (var i = 0; i < window.jQuery_store.length; ++i) {
        try {
            window.jQuery_store[i]();
        } catch (err) {
            console.log(err);
        }
    }
})

加載此腳本后,它將:

  • 等到jQuery可以安全使用
  • 將用一個新的 jQueryReady 替換 function jQueryReady ,它只是立即調用委托(jQuery 在給定的時間准備好)。
  • 遍歷從以前jQueryReady調用中保存的函數。

3.將所有內容放在一起 僅在加載 jQuery 后才加載 jquery-ready.js。 在您的頁腳中,您將擁有:

<script defer src=".../jquery.min.js">
<script defer src=".../bootstrap.min.js">
... any other plugins for jQuery you probably need
<script defer src=".../jquery-ready.js">

這確保 jquery-ready.js 腳本僅在 jQuery 執行后才會執行。

用法

您現在可以隨時使用 jQueryReady function。

jQueryReady(function() {
    // jQuery is safe to use here
    $("div.to-be-hidden").hide();
})

看來您只需要<script defer>http://www.w3schools.com/tags/att_script_defer.asp

看看jQuery.holdReady()

“保持或釋放 jQuery 的就緒事件的執行。” (jQuery 1.6+)

http://api.jquery.com/jQuery.holdReady/

我想在 WordPress 站點上延遲加載 jQuery,所以我實際上無法使用它更新所有參考。 相反,編寫了一個小包裝器來排隊 jQuery 調用,然后在最終加載時調用。 把它放在頭部,只有 250 字節左右,這意味着 jQuery 可以在不改變所有現有引用的情況下被延遲或異步加載。 讓我的加載時間更好。

我的快速代碼可能不適用於所有 jQuery 功能,但到目前為止,除了我嘗試過的一個 function 調用之外,它已經適用於所有功能。 通常我會做這樣的自定義東西,我不會讓它可用,但我想我會把這個片段放到網上。 可在此處獲得 https://github.com/andrewtranter/jQuery_deferred_compat

使用http://labjs.com 加載 html末尾的所有腳本,這是 100% 的解決方案,我根據 gtmetrix 規則對其進行了多次測試。 例如http://gtmetrix.com/reports/interactio.cz/jxomHSLV

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM