第一章 加載和執行

第一章 加載和執行


大多數瀏覽器是使用單進程來處理UI和javascript,因此無法並行下載,當瀏覽器讀取到javascript時會先下載javascript在進行頁面的渲染,javascript讀取的時間有多長,頁面停止渲染的時間就有多長。因爲在javascript中有可能會進行DOM操作。爲了保證瀏覽器能呈現出準確的界面,所以會先下載javascript。

1.腳本的位置

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript" src="f1.js"></script>
    <script type="text/javascript" src="f2.js"></script>
    <script type="text/javascript" src="f3.js"></script>
     <link rel="stylesheet" href="style.css"/>
</head>
<body>

</body>
</html>

瀏覽器在遇到body標籤之前是不會進行頁面渲染的,因此瀏覽器會按照順序下載javascript。在一個大型網站中會加載很多腳本。如果先下載並javascript的話,那麼頁面會出現一片空白。下面是上述代碼的瀑布流圖

這裏寫圖片描述

可以看出每個腳本都是在上個腳本下載並執行完後再開始下載的。
解決措施:將腳本儘量加載靠近標籤底部的位置。儘可能的減少對整個頁面下載的影響。

2.成組的腳本


每個http請求會產生額外的性能負擔。下載一個100KB的文件要比下載四個25KB的文件要快,所以我們要儘量將腳本合併。
解決措施:使用打包工具儘可能的將腳本合併,減少http請求,減少性能的負擔。

3.非阻塞腳本


保持較小體積的腳本,減少http請求只是創建反應迅速網站的第一步,功能越多的網站所需要的javascript代碼體積就會越大。儘管將所有代碼合併,只進行一次http請求,也會需要很長時間,在這期間,頁面會出現空白。因此可以將腳本逐步添加。
解決措施
1.使用延遲腳本,即defer屬性,直到文檔載入並解析完成纔會執行
1.使用異步腳本,即async屬性,瀏覽器儘快執行腳本,但不阻塞文檔解析

defer:
優勢:帶有defer屬性的script會告訴瀏覽器,腳本中沒有影響dom的代碼,可以延遲執行。當腳本解析到script標籤時腳本會被下載。帶有defer屬性的腳本支持和其他資源並行下載。但是不會執行,直到dom節點加載完成後纔會執行。(onload事件之前)
缺點:因爲defer屬性只支持ie4或者firefox3.5以上因此並不是一個優秀的跨瀏覽器的解決方案,在不支持defer屬性的瀏覽器中script依舊會阻塞dom的加載。

async:
defer和async一樣,在下載的同時其他資源也可以並行下載。區別就在於,帶有async屬性的腳本,當下載完後會立刻執行。因此可能不會按照順序進行加載。如果腳本之間相互依賴可能會出現undifined或者報錯。

目前來看,最新版本的firefox和chrome(還有同樣webkit內核的safari),IE的話對於defer是一直都支持的,async屬性IE6~9都沒有支持(IE10毫無疑問的會支持),onload是在IE9中新加入的屬性.

4.動態添加腳本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<input type="button" onclick="init()"/>

<script type="text/javascript">
  var script=document.createElement('script');
   script.type='text/javascript';
   script.src='fn.js';
   document.getElementsByTagName('head')[0].appendChild(script);
   script.οnlοad=function(){
    _fn();
   };
  _fn();//報錯
  setTimeout(function(){
      _fn()
  },200)
</script>
</body>
</html>

當腳本進行下載的同時不會阻塞頁面其他資源的下載和代碼的執行,因此,如果加載的腳本中有需要下面代碼所調用的接口,則會出現錯誤。因此需要通過事件進行調用。
在firefox,chorme,opera都提供了onload事件供調用
在ie中提供了onreadychange事件,readystate伴隨着狀態一共有五種取值。

uninitialized:默認狀態
loading:開始下載
loaded:下載完成
interactive:下載完成且不可用
complete:所有數據已經準備好

  function _loadscript(url,callback){
      var script=document.createElement('script');
      script.type='text/javascript';
      script.src=url;
      if(script.readyState){
          script.onreadystatechange=function(){
              if(script.readyState=='loaded'||script.readyState=='complete'){
                  script.onreadystatechange=null;
                         callback()
              }
          }
      }
      else{
          script.οnlοad=function(){
              callback();
          }
      }
      document.getElementsByTagName('head')[0].appendChild(script);
  }

5.XHR腳本注入


另一種無阻塞加載腳本的方式是通過XMLHttpRequest(XHR)對象獲取腳本並注入到頁面中:先創建一個XHR對象,然後用它下載JavaScript文件,然後通過創建動態script元素將代碼注入到頁面中。

var xhr = new XMLHttpResquest();
xhr.open("get","file.js",true);
xhr.onreadystatechange = function(){
    if(xhr.readyState == 4){
        if(xhr.status>=200 && xhr.status<300 || xhr.status == 304){
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.text = xhr.responseText;
            doument.body.appendChild(script);
        }
    }
}
xhr.send(null);

總結


將script標籤放在頁面底部,body閉合之前
合併腳本
使用無阻塞加載方式:defer,async屬性,動態創建script標籤,XHR對象注入JavaScript代碼

發佈了38 篇原創文章 · 獲贊 12 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章