1. 程式人生 > 實用技巧 >從瀏覽器內部執行機制看效能優化

從瀏覽器內部執行機制看效能優化

瞭解瀏覽器背後的執行機制

瞭解瀏覽器背後的執行機制就是了解瀏覽器的核心,現在市面上主流瀏覽器的核心名稱分別如下:

  • chrome: blink核心
  • Opera: blink核心
  • Safari: webkit核心
  • FireFox: Gecko核心
  • IE: Trident核心

** 注:blink核心其實是基於webkit核心衍生出的一個新分支 **

獲取到的html/css/js資源經過瀏覽器核心的處理生成影象呈現在瀏覽器上,那麼下面我們就詳細說說瀏覽器核心在拿到資源之後是經過哪些處理來生成我們最終所看到的頁面。

瀏覽器核心主要的功能模組

瀏覽器在處理資源的過程中是由多個模組協同工作的,主要關注下面幾個模組:

  • html解析器:解析HTML檔案,最終輸出DOM樹
  • css解析器:解析CSS檔案,最終輸出樣式層疊表
  • 圖層佈局計算模組:佈局計算每個物件的大小和位置
  • 檢視繪製模組:將圖層佈局計算模組的結果形成畫素並繪製到螢幕上
  • js模組:編譯和執行js

瀏覽器渲染過程

  • 解析HTML:執行所有的載入邏輯,在解析HTML的過程中發出渲染頁面所需的所有請求。
  • 計算樣式:解析CSS檔案,生成層疊樣式表並於HTML結合生成渲染樹(:before,:after這樣的偽類是在該過程中生成的)
  • 計算圖層佈局:精確計算所有DOM節點的大小以及在頁面中的位置
  • 繪製圖層:在這一步瀏覽器會根據上一步結果將各個圖層轉化成畫素,並對所有媒體檔案進行解碼
  • 整合圖層,生成頁面:瀏覽器合成所有圖層,將資料由cpu傳遞給GPU進行影象的繪製。

上面整個過程就是瀏覽器渲染頁面的主要過程,在這個過程中主要是按順序生成了下面幾棵樹:

  • DOM樹:DOM樹是瀏覽器解析HTML,將HTML標籤抽象成的一顆樹。
  • CSS樹:CSS樹是瀏覽器解析CSS,根據內容生成的一顆樹,生成CSS樹是和DOM樹並行的。
  • Render樹:是由DOM樹和CSS樹相整合,形成的一顆渲染樹。
  • 佈局渲染樹:瀏覽器根據Render樹遞迴計算,確定DOM樹上每個節點的位置和大小形成的一顆佈局渲染樹。
  • 繪製渲染樹:GPU根據佈局渲染樹結果進行影象繪製形成的一顆樹。

基於渲染過程的CSS優化

在渲染過程這部分內容我們瞭解到在渲染過程中會根據CSS來形成CSS樹,那麼能在這個過程中做哪些優化呢?在說明CSS優化的方法之前先介紹一下CSS的解析規則。

我們在編寫css的過程中,一般是從左到右去進行編寫,比如我們想給類名為test_parent下的p標籤去增加樣式的時候,一般會這樣寫:

.test_parent p {
    font: 16px/20px Microsoft YaHei;
}

但是這樣些會造成很大的效能問題,為什麼呢?因為瀏覽器在解析CSS的過程中對於宣告是從右往左進行匹配的。對於上面這種寫法瀏覽器的做法會先找到DOM樹中的所有標籤為p的節點,然後再去這些p節點中去找哪些p節點的父節點的類為test_parent。由於p節點在我們的頁面中可能會有很多很多,這樣就導致尋找的過程會變長。

從上面的內容中我們就可以得出第一個CSS優化的思路,優化css宣告的編寫,有下面幾種優化方式:

    1. 不使用萬用字元*,因為萬用字元會讓瀏覽器去遍歷樹節點中的每一個節點。
    1. 儘量少使用標籤選擇器,用類選擇去代替
    1. 減少巢狀,因為巢狀的層級越深,瀏覽器遍歷的層級就越深

介紹完css選擇器的優化之後,我們再來回想一下上面的渲染過程,頁面形成的過程中一顆重要的樹Render樹是由DOM樹和CSS樹合力生成的,那麼如果沒有CSS樹Render樹也就不會形成,更不必談最終的頁面了,所以第二個優化思路就是儘快讓CSS樹去形成,而CSS樹的形成是瀏覽器解析CSS檔案生成的,那麼為了讓CSS樹形成,我們可以採取下面的方式去優化:

  • 儘早的去載入CSS檔案,也就是我們平常將所有的CSS檔案放在head標籤中去載入。

至此我們已經對CSS樹的形成和Render樹的形成做了優化,那麼CSS還有可優化的點嗎?答案是有的,在上述的渲染過程中在Render樹後面還形成了一棵佈局渲染樹,那麼在這棵樹的形成過程中我們能做哪些優化呢?佈局渲染樹是瀏覽器根據Render樹去計算每個DOM節點的大小以及所在頁面中的位置,這些計算是依賴我們編寫的css宣告,比如:

.wrap {
    position: relative;
    height: 100px;
    background-color: #ff0000;
}

為了能夠讓瀏覽器快速的計算節點的位置和大小我們應該遵循CSS的宣告順序:

  • 顯隱屬性:display || visibility(如果display:none,瀏覽器就不會去計算大小和位置了)
  • 定位屬性:position、top、left、bottom、right、z-index、float、clear(這些屬性影響了節點的位置,越早去些,瀏覽器越早去計算)
  • 盒模型:width、height、padding、margin、border(這些屬性影響了節點的大小,越早寫的化,瀏覽器可以越早去計算)
  • 排版:line-height、text-align、font等
  • 視覺:color、background-color等

至此關於CSS的優化已經結束了,下面來說說渲染過程中JS的一些優化

廣州vi設計公司 http://www.maiqicn.com 我的007辦公資源網 https://www.wode007.com

基於渲染過程的JS優化

看到這我們會發現上面很少提及JS,不是JS不重要哈,是在渲染過程中JS基本上不需要,那麼為什麼要提及JS呢,因為JS會阻塞HTML的解析,比如下面這段程式碼

<body>
    <div>js之前的html</div>
    <script>
       console.log('js執行了');
    </script>
    <div>js之後的html</div>
</body>

瀏覽器解析時,遇到上面的js時瀏覽器會把控制權交給js引擎,這時瀏覽器就會停止DOM樹的解析。這樣就延遲了DOM樹的生成。那麼對於這種情況我們有哪些優化呢?

  • 1.將js放在最後去編寫或者引用,這也是我們經常去做的。
  • 2.合理的使用async和defer引入js

async和defer的作用:

  • async:非同步載入,載入成功之後立馬執行,也就是說script標籤中增加async會使js在載入過程中不會阻止dom的解析
  • defer:非同步載入,等HTML載入完成之後再執行