JavaScript >> Javascript 文檔 >  >> JavaScript

無阻塞加載 JavaScript

我正在閱讀 Steve Souder 關於加載腳本而不阻塞的博客文章,他在其中指出動態創建 <script> 元素並分配其 src 屬性導致下載不會阻止其他下載或頁面進程。他的帖子缺少一個如何做到這一點的例子,所以我想我會從那裡開始。我認為大多數開發人員傾向於將 JavaScript 庫用於此類行為(想到 YUI Get 實用程序),但了解底層技術的討論仍然很有用。

無阻塞下載 JavaScript 的基本方法非常簡單:

var script = document.createElement("script");
script.type = "text/javascript";
script.src = "file.js";
document.body.appendChild(script);

這非常簡單,您只需創建一個新的 DOM 元素,分配其屬性並將其添加到頁面中。這段代碼有兩點需要注意。首先,直到 script 才真正開始下載 節點被添加到文檔中。這與動態創建 <img> 不同 元素,為其分配 src 甚至在節點添加到文檔之前自動開始下載。第二點要注意的是,您可以將腳本節點添加到 <head><body>;真的沒關係。這就是動態加載 JavaScript 文件而不阻塞頁面所需的全部內容。

當然,您可能還希望在 JavaScript 文件完全下載和執行時收到通知,這就是事情變得有點棘手的地方。大多數現代瀏覽器(Firefox、Safari、Opera、Chrome)都支持 load <script> 上的事件 元素。這是確定腳本是否已加載的簡單方法:

//Firefox, Safari, Chrome, and Opera
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "file.js";
script.onload = function(){
    alert("Script is ready!");
};
document.body.appendChild(script);

真正的問題在於 Internet Explorer,它使用 readyState 屬性來指示腳本的狀態和一個 readystatechange 事件以指示該屬性何時更改。在這種情況下,readyState 不是 XMLHttpRequest 中的數字 目的;相反,它是五個可能的值之一:

  • “未初始化”——默認狀態。
  • “加載中”——下載已開始。
  • “已加載”- 下載已完成。
  • “交互式”——數據完全可用,但不完全可用。
  • “完成”——所有數據都可以使用了。

即使 MSDN 文檔指出這些是 readyState 的可用值 ,實際上,您永遠不會看到所有這些。該文檔也適用於也支持 readyState 的其他元素 並讓我們對哪個 readyState 進行了相當神秘的描述 期望值:

更奇怪的是最後的 readyState 並不總是 complete .有時,readyState 停在 loaded 無需繼續complete 有時它會跳過 loaded 共。最好的方法是同時檢查 readyState 值並在這兩種情況下刪除事件處理程序,以確保您不會處理兩次加載:

//Internet Explorer only
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "file.js";
script.onreadystatechange = function(){
    if (script.readyState == "loaded" ||
            script.readyState == "complete"){
        script.onreadystatechange = null;
        alert("Script is ready!");
    }
};
document.body.appendChild(script);

你可以很容易地包裝這兩種方法來創建一個跨瀏覽器的函數來動態加載 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);
}

要使用它,只需傳入要檢索的 URL 和加載後調用的函數:

loadScript("http://yui.yahooapis.com/2.7.0/build/yahoo/yahoo-min.js",
    function(){
        YAHOO.namespace("mystuff");

    //more...
});

以這種方式加載腳本可以防止它們阻止頁面上其他資源的下載或阻止顯示呈現。當性能很重要時,這是一種非常有用的技術(讓我們面對現實吧,什麼時候從來沒有?)。真正酷的是 YUI 3 完全圍繞非阻塞 JavaScript 下載的理念構建。您只需下載~20KB 的種子文件,然後指定要加載的其他資源,例如:

YUI().use("dom", function(Y){
    Y.DOM.addClass(document.body, "active");
});

在幕後,YUI 為 dom 構造適當的 URL 模塊並下載它,當代碼準備好時自動執行回調函數。通過異步下載其餘的 JavaScript 代碼,這確實可以提高整個頁面的初始下載時間。

在不阻塞的情況下加載 JavaScript 是理解和在關注頁面加載性能的 Web 應用程序中使用的一項非常重要的技術。 JavaScript 阻塞會減慢整個用戶體驗,但它不再必須這樣做。


Tutorial JavaScript 教程
  1. 在 NestJS 中使用數據庫進行自定義驗證

  2. 帶有類組件的 Vuex

  3. 我如何製作一個工具來快速為我的博客創建封面圖片

  4. DVD角反彈,但更令人滿意📀

  5. 如果語句將 FALSE 承諾視為 TRUE

  6. 如何使用 Three.js 創建天空盒

  7. 動態創建元素的事件綁定?

  1. ReactJS for Beginners #05 - 使用 REST API 進行通信

  2. Vuex:為什麼我們需要 SPA 狀態管理

  3. PHP 與 JavaScript – 項目的最佳選擇

  4. 改進自動化測試的 10 種意想不到的方法

  5. 如何使用 JavaScript 模擬單擊以使當前輸入失去焦點

  6. 如何在 javascript 中使用 .bind()。

  7. 如何檢查 ES6 Map 或 Set 是否為空?

  1. 使用 React、Redux 和 SVG 開發遊戲 - 第 2 部分

  2. Dev hack:在瀏覽器中查看難以查看的圖像

  3. 將 NextAuth.js 與魔術鏈接一起使用

  4. VueJS:開始一個新項目