《高效能JavaScript》讀書筆記①載入和執行

pswyjz發表於2021-09-09

JavaScript的載入和執行(Loading and Execution)

JavaScript的阻塞特性

  • 當瀏覽器遇到JavaScript程式碼段時(不管是內嵌還是外鏈),由於不確定其是否會進行DOM操作,所以都會等待指令碼的解析和執行完成後,再往下執行。此時頁面渲染和使用者互動都是被阻塞的,這就是 JavaScript的阻塞特性

JavaScript阻塞特性的思考

  • 雅虎效能小組對JS程式碼最佳化的首要規則就是,透過改變

    指令碼的位置來減少對頁面載入的影響。也就是說將
    元素放到標籤底部,這樣頁面的CSS和圖片等資原始檔載入時,就不需要等待JS程式碼的解析和執行了。

  • 除此之外,減少

    標籤的數量也能改善阻塞的情況

  1. 我們可以合併

    程式碼段,因為瀏覽器在解析HTML頁面時,每遇到一個
    標籤,都會因為執行指令碼而導致一定的延時。

  2. 我們還需要儘可能的合併外鏈的JavaScript檔案。測試發現,下載一個100KB的JS檔案比下載四個25KB的JS檔案要快,是因為每次HTTP請求相當於重新進行一次Socket連線,會產生效能損耗。

實現Noblocking Scripts(無阻塞的指令碼)的幾種方式

  • Deferred Scripts (指令碼延遲)
    針對JavaScript的阻塞特性,很多人首先想到的辦法可能是:能不能先下載JS檔案,等頁面載入完成後,再去解析和執行引入的JavaScript程式碼呢?
    針對此種設想,HTML4標準為

    標籤提供了defer屬性。意味著可以先下載JS檔案(同時允許並行下載),等到DOM載入完成(即事件被觸發前),才會執行其中的程式碼段。

    注意:該屬性只對宣告瞭src屬性的

    標籤生效,另外HTML5規範中引入了async屬性,和defer屬性一樣,也是用於非同步載入指令碼的

  • Dynamic Script Elements (動態指令碼元素)
    我們知道DOM(文件物件模型)機制使得我們可以動態的建立、編輯、移動和刪除HTML元素,這裡面當然也包含

    元素。也就是說,其實我們是可以透過JavaScript程式碼來動態構建
    標籤的。

    //建立script元素var script = document.creatElement("script"); 
    //指定元素的type屬性script.type = "text/javascript"; 
    //指定URLscript.src = "file1.js"; 
    //將新的script標籤加入到文件頭部document.getElementByTagName("head")[0].appendChild(script);

    注意,當新的

    元素被加入到時,會立即開始下載file1.js檔案,並執行其中的JS指令碼。這種方式的優勢就在於,能夠把
    指令碼放在頁面區域,避免影頁面其他部分的載入。
    如果需要監聽指令碼的下載狀態,可以透過()方法監聽指令碼載入完成的狀態:

    var script = document.creatElement("script");
    script.type = "text/javascript";//js下載完畢後的監聽(IE中不可用)script. = function(){
        alert("script loaded!");
    };
    script.src = "file1.js";document.getElementByTagName("head")[0].appendChild(script);

    但是()方法僅在Firefox、Chrome、Opera和Safari3+ 瀏覽器中支援,如果想在IE瀏覽器要監聽js指令碼的下載狀態,則可以透過監聽

    元素的readyState狀態屬性來實現。
    readyState有五種取值,但是微軟的相關文件表明,在整個
    元素生命週期中,並非readyState的每個值都會用到。最終表明
    元素載入完畢的是"loaded"和"complete"兩個狀態,所以我們要檢查這兩個狀態。

    var script = document.creatElement("script");
    script.type = "text/javascript";//js下載完畢後的監聽(IE)script.onreadystatechange = function(){    if(script.readyState == "loaded" || script.readyState == "complete"){
            alert("script loaded!");
        }
    }

    由此可見透過動態指令碼元素的方式解決JavaScript的阻塞問題時,如果需監聽下載狀態,還需要針對不同瀏覽器做封裝處理。

    //定義公共的js載入方法(有沒有覺得這種callback的方式和$.Ajax很類似?)function loadScript(url,callback){    var script = document.creatElement("script");
        script.type = "text/javascript";    //判斷如果能獲取readyState屬性,則表明是IE瀏覽器
        if(script.readyState){
         script.onreadystatechange = function(){         if(script.readyState == "loaded" || script.readyState == "complete"){
             script.onreadysatechange = null;
             callback();
         }
         }    //其他瀏覽器
        }else{
         script. = function(){
         callback();
         }
        }
        script.src = url;    document.getElementByTagName("head")[0].appendChild(script);
    }//呼叫loadScript("file1.js",function(){
     alert("script loaded!");
    });
  • XMLHttpRequest Script Injection (XMLHttpRequest指令碼注入)
    另一種無阻賽載入指令碼的方式,是使用XMLHttpRequest(XHR)物件載入JS指令碼
    由於XMLHttpRequest指令碼注入的方式,由JS指令碼的載入以及

    元素的建立兩部分組成,我們就可更加靈活的控制JavaScript指令碼,比如先載入,等到需要時候再執行。


//建立XMLHttpRequest物件
var xhr = new XMLHttpRequest();
//透過GET請求載入file1.js
xhr.open("get","file1.js",true);
//透過XHR物件的onreadystatechange()方法監聽readState屬性的變化
xhr.onreadystatechange = function(){
//readyState屬性表示XHR物件請求的就緒狀態:0-請求未初始化;1-請求已建立;2-請求已傳送;3-請求處理中;4-響應已完成
if(xhr.readyState == 4){
//status屬性表示HTTP請求的狀態碼:200-(OK)請求成功;304-(Not Modified)從快取中讀取;狀態碼小於300都表示請求成功
if(xhr.status >= 200 && (xhr.status //建立script元素
var script = document.creatElement("script");
//指定元素的type屬性
script.type = "text/javascript";
//將response響應內容填充到script元素中
script.text = xhr.responseText;
//當把script元素新增到body時,js程式碼會被立即執行
document.body.appendChild(script);
}
}
}
```



作者:梁同學de自言自語
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/755/viewspace-2813618/,如需轉載,請註明出處,否則將追究法律責任。

相關文章