從瀏覽器內部運行機制看性能優化

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

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

  • 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的一些優化

基於渲染過程的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加載完成之後再執行。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章