瀏覽器加載和渲染HTML的過程(標準定義的過程以及現代瀏覽器的優化)

先看一下標準定義的瀏覽器渲染過程(網上找的):javascript

瀏覽器打開網頁的過程

  1. 用戶第一次訪問網址,瀏覽器向服務器發出請求,服務器返回html文件;
  2. 瀏覽器開始載入html代碼,發現 head 標籤內有一個 link 標籤引用外部CSS或JS文件;
  3. 瀏覽器又發出CSS及JS文件的請求,服務器返回這個CSS,JS文件;
  4. 瀏覽器繼續載入html中 body 部分的代碼,而且CSS,JS文件已經拿到手了,能夠開始渲染頁面了;
  5. 瀏覽器在代碼中發現一個 img 標籤引用了一張圖片,向服務器發出請求。此時瀏覽器不會等到圖片下載完,而是繼續渲染後面的代碼
  6. 服務器返回圖片文件,因爲圖片佔用了必定面積,影響了頁面佈局,所以瀏覽器須要回過頭來從新渲染這部分代碼;
  7. 瀏覽器發現了一個包含一行Javascript代碼的 script 標籤,趕快執行它;
  8. Javascript腳本執行了這條語句,它命令瀏覽器隱藏掉代碼中的某個 div (style.display=」none」)。杯具啊,忽然就少了這麼一個元素,瀏覽器不得不從新渲染這部分代碼;
  9. 終於等到了 html 的到來,瀏覽器淚流滿面……

瀏覽器加載和渲染html的順序

  1. IE瀏覽器下載的順序是從上到下,渲染的順序也是從上到下,下載和渲染是同時進行的。
  2. 在渲染到頁面的某一部分時,其上面的全部部分都已經下載完成(並非說全部相關聯的元素都已經下載完)
  3. 若是遇到語義解釋性的標籤嵌入文件(JS腳本,CSS樣式),那麼此時IE的下載過程會啓用單獨鏈接進行下載。
  4. 而且在下載後進行解析,解析過程當中,中止頁面全部往下元素的下載,阻塞加載
  5. 樣式表在下載完成後,將和之前下載的全部樣式表一塊兒進行解析,解析完成後,將對此前全部元素(含之前已經渲染的)從新進行渲染。
  6. JS、CSS中若有重定義,後定義函數將覆蓋前定義函數。

JS的加載

  • 不能並行下載和解析(阻塞下載)
  • web的模式是同步的,開發者但願解析到一個script標籤時當即解析執行腳本,並阻塞文檔的解析直到腳本執行完;若是腳本是外引的,當引用了JS的時候,瀏覽器發送一個js request就會一直等待該request的返回,這個過程也是同步的,會阻塞文檔的解析直到資源被請求到。由於瀏覽器須要一個穩定的DOM樹結構,而JS中頗有可能有代碼直接改變了DOM樹結構,好比使用 document.write 或 appendChild,甚至是直接使用的location.href進行跳轉,瀏覽器爲了防止出現JS修改DOM樹,須要從新構建DOM樹的狀況,因此就會阻塞其餘的下載和呈現。這個模式保持了不少年,而且在html4及html5中都特別指定了。開發者能夠將腳本標識爲defer,以使其不阻塞文檔解析,並在文檔解析結束後執行。Html5增長了標記腳本爲異步的選項,以使腳本的解析執行使用另外一個線程。

 

這裏面有幾個點須要說明一下:css

  1.咱們知道瀏覽器的處理過程是解析html生成DOM tree->根據DOM tree和樣式表生成render tree->渲染render tree展現。瀏覽器爲了讓用戶更快的看到頁面,因此是邊解析html生成局部的DOM tree,瀏覽器就生成部分render tree而後展現出來。html

  2.此過程當中有兩種外部資源是阻塞腳本執行,從而阻塞渲染的,分別是外部js和外部css。外部js是阻塞了DOM tree的生成,由於瀏覽器須要一個穩固的DOM tree,而js可能破壞這個結構(固然其中也可能會更改樣式【注意是樣式而不是樣式表】,可是這個不阻塞也不會有影響的);外部css樣式表也會阻塞腳本的執行,理論上,既然樣式表不改變Dom樹,也就沒有必要停下文檔的解析等待它們,然而,存在一個問題,腳本可能在文檔的解析過程當中請求樣式信息,若是樣式尚未加載和解析,腳本將獲得錯誤的值,顯然這將會致使不少問題,這看起來是個邊緣狀況,但確實很常見。Firefox在存在樣式表還在加載和解析時阻塞全部的腳本,而Chrome只在當腳本試圖訪問某些可能被未加載的樣式表所影響的特定的樣式屬性時才阻塞這些腳本。html5

  3.其他外部資源是不阻塞渲染的,好比圖片,咱們能看到不少時候頁面大致的框架都呈現出來了,就是圖片的位置沒有顯示出來的狀況,等到圖片下載下來之後再從新渲染。java

 

現代瀏覽器的優化:jquery

  按照標準的瀏覽器渲染和下載過程。下面的代碼加載外部資源的順序應該和資源在html中的順序一致。其中head中添加了一個外部資源請求http://hm.baidu.com/hm.js?a041a0f4ff93aef6aa83f34134331a1d應該在全部樣式以前加載  web

<html>
<head>
    ...
    <!--百度統計代碼-->
    <script>
    var _hmt = _hmt || [];
    (function() {
        var host=document.location.hostname;
        if(/lcfarm.com$/ig.test(host)){
          var hm = document.createElement("script");
          hm.src = "//hm.baidu.com/hm.js?a041a0f4ff93aef6aa83f34134331a1d";
          var s = document.getElementsByTagName("script")[0]; 
          s.parentNode.insertBefore(hm, s);
        }
    })();
    </script>
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/pkg/index.html_aio_f9db6a6.css">
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/common/css/common_530eedd.css">
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/css/index_8b620da.css">
    <link rel="stylesheet" type="text/css" href="//static.lcfarm.com/pc-dist/pkg/index.html_aio_2_2379650.css">
</head>
<body>
    ...
    <script type="text/javascript" data-loader="" src="//static.lcfarm.com/pc-dist/common/dep/mod_36ad799.js"></script>
    <script type="text/javascript" data-loader="" src="//static.lcfarm.com/pc-dist/common/dep/jquery_c07f226.js"></script>
    <script type="text/javascript" src="//static.lcfarm.com/pc-dist/common/js/jquery/jquery.cookie_546183c.js"></script>
    <script type="text/javascript" src="//static.lcfarm.com/pc-dist/pkg/common_85ea494.js"></script>
    <script type="text/javascript" src="//static.lcfarm.com/pc-dist/pkg/index.html_aio_350303c.js"></script>
</body>
</html>

  可是實際上在chrome。Firefox、ie8+等瀏覽器中卻發現是以下效果(使用https://www.webpagetest.org/測試)chrome

  

  爲何?這就是預解析(Speculative parsing)瀏覽器

  Webkit和Firefox都作了這個優化,當執行腳本時,另外一個線程解析剩下的文檔,並加載後面須要經過網絡加載的資源。這種方式可使資源並行加載從而使總體速度更快。須要注意的是,預解析並不改變Dom樹,它將這個工做留給主解析過程,本身只解析外部資源的引用,好比外部腳本、樣式表及圖片。服務器

  如上面的那張圖,能夠看出在執行腳本的時候與解析了一大堆的外部資源引用,並啓動線程下載他們,主線程還在等待hm.js的返回。

 

  若是以爲本文不錯,請點擊右下方【推薦】!

相關文章
相關標籤/搜索