腳本無阻塞加載策略

       從上圖可以看出,當瀏覽器遇到<script>標籤時,瀏覽器會停止處理頁面,先執行Javascript代碼,然後再繼續解析和渲染頁面。在這個過程中,頁面和用戶的交互完全被阻塞了。通常表現爲顯示空白頁面,用戶無法瀏覽內容。

      現在的瀏覽器都支持並行下載文件,比如上圖同時下載多個圖片。而且,IE8 、FireFox3.5、Safari4和Chrome2都支持並行下載javascript文件,但是javascript文件的下載會阻塞其他資源的下載。儘管腳本的下載過程不會相互影響,但是頁面仍然需要等待javascript的執行完畢才能繼續。因此,儘管最新的瀏覽器通過並行下載提高了性能,但是腳本阻塞問題仍然沒有解決。

     解決辦法有:

    1. 把<script>標籤放到</body>閉合之前   

    由於腳本會阻塞其他資源的下載,因此推薦把所有的<script>標籤儘可能的放到<body>標籤的底部,以儘量減少對整個頁面下載的影響。這是雅虎性能小組提出的優化JavaScript的首要規則:把腳本放在底部。

    2. 腳本合併,減少<script>標籤的數量  

    每次遇到<script>標籤,瀏覽器都要發一次HTTP請求。而HTTP請求耗時是web性能的最大的影響之一。

    3. 腳本延遲加載

    HTML 4爲<script>標籤定義了一個擴展屬性:defer。defer 屬性規定當頁面已完成加載後,纔會執行腳本。目前所有主流瀏覽器都支持defer。注意:defer 屬性僅適用於外部腳本(只有在使用 src 屬性時)。

    一個帶有defer屬性的<script>標籤可以放置在文檔的任何位置,它會在被解析時啓動下載,直到DOM加載完成(在onload事件句柄被調用之前)。當一個defer的Javascript文件被下載時,它不會阻塞瀏覽器的其他處理過程,所以這些文件可以與其他資源一起並行下載。

   除了defer屬性外,HTML 5 規範中引入了async屬性,用於異步加載腳本。async與defer的相同點是採用並行下載,在下載過程中不會產生阻塞。區別在於執行時機,async是加載完成後自動執行,而defer需要等待頁面完成後執行。這就會造成腳本的執行順序和頁面上腳本的排放順序不一致,可能造成腳本依賴的問題(指async)

   4. 動態腳本加載

   DOM允許我們使用Javascript動態創建HTML的幾乎所有文檔內容,一個新的<script>元素可以非常容易的通過標準DOM創建:

  var script=document.createElemetn("script");
 
  script.type="text/javascript";
 
  script.src="file.js";;
 
  document.getElementsByTagName("head").appendChild(script);

 

    新的<script>元素加載file1.js源文件。此文件當元素添加到頁面後立刻開始下載。此技術的重點在於:無論在何處啓動下載,文件的下載和運行都不會阻塞其他頁面處理過程。

    當文件使用動態腳本節點下載時,返回的代碼通常立即執行(除了Firefox和Opera,它們將等待此前的所有動態腳本節點執行完畢)。

    大多數情況下,我們希望調用一個函數就可以實現Javascript文件的動態下載。下面的函數封裝實現了標準實現和IE實現:

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.getElementsByTagName("head")[0].appendChild(script);   
 }  
 
loadScript("file1.js", function(){  //調用  
    alert("File is loaded!");   
}); 

    如果需要加載多個js文件,一定要考慮清楚文件的加載順序。你可以將下載操作串聯起來以確保下載順序:

loadScript("file1.js",function(){
      loadScript("file2.js",function(){
         loadScript("file3.js",function(){
          alert("ok");
          });
      }); 
 });

    此函數接受兩個參數:Javascript文件的Url和一個當Javascript接收完成時觸發的回調函數。屬性檢查用於決定監視哪種事件。最後一步src屬性,並將javascript文件添加到head。

    動態腳本加載憑藉它在跨瀏覽器兼容性和易用的優勢,成爲最通用的無阻塞加載解決方案。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章