來源於:http://yangfch3.com/2017/03/04/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%86%85%E6%A0%B8%E3%80%81%E9%A1%B5%E9%9D%A2%E5%91%88%E7%8E%B0%E5%8E%9F%E7%90%86%E5%8F%8A%E5%85%B6%E4%BC%98%E5%8C%96/javascript
介紹瀏覽器內核、頁面呈現原理等基礎知識,同時根據原理提出頁面呈現優化方案。css
瀏覽器內核又叫渲染引擎,主要負責 HTML、CSS 的解析,頁面佈局、渲染與複合層合成。瀏覽器內核的不一樣帶來的主要問題是對 CSS 的支持度與屬性表現差別。html
如今主流的內核有:Blink、Webkit、Gecko、EdgeHTML、Trident,這裏面有幾個須要注意的地方:java
Blink 是在 Webkit 的基礎上的改進,是如今對新特性支持度最好的內核git
移動端基本上所有是 Webkit 或 Blink 內核(除去 Android 上騰訊家的 X5),這兩個內核對新特性的支持度較高,因此新特性能夠在移動端大展身手。github
Trident 是 IE4+ 的內核,一直持續到 IE11,EdgeHTML 是微軟拋棄 IE 後開發的全新內核web
更多資料請看附錄表格chrome
通常現代瀏覽器都會有如下幾種渲染模式:canvas
在 IE5 與 NS4 那個年代,瀏覽器大戰,標準未立,Web 則在經歷早期快速地發展。segmentfault
後來標準逐步創建,新標準的規範與之前 IE五、NS4 的實現存在着不可避免的差別差別,可是此時的網絡世界許許多多舊時的頁面正在運行,若是按照新標準的實現來渲染的話會有大量的問題出現。
因此此時大部分現代瀏覽器廠商想到了區別性地使用不一樣渲染模式來對待這些 Web 頁面。
而 IE 隨着升級,對現代標準的支持也愈來愈完善,因此 IE 爲了正常渲染舊時頁面,支持咱們指定哪一個版本的 IE 模式來渲染頁面。
總結就是:
標準未立以前,HTML 文檔是沒有文檔頭的,同時在 HTML5 以前的 HTML4/3 的文檔頭都有各自的特徵,因此在大部分現代瀏覽器下觸發的機制以下:
無 DOCTYPE
頭觸發怪異模式
DOCTYPE
頭不正確(不是 html)也觸發怪異模式
如:
<!DOCTYPE svg>
DOCTYPE
頭爲 HTML3 頭觸發怪異模式
DOCTYPE
頭爲 HTML4 頭則觸發接近標準模式(或稱有限怪異模式)
常見的 HTML5 DOCTYPE 聲明則使用標準模式
在 IE 下,除了文檔頭的差別能夠自動觸發渲染模式的選擇,咱們還能手動指定(在 IE8+ 適用)使用哪一個版本的 IE 渲染模式來渲染咱們的頁面(擴展閱讀):
1
2
3
4
5
6
7
8
9
|
<!-- 使用當前操做系統已裝的最新的 IE -->
<!-- chrome=1 是針對雙核瀏覽器使優先使用 Chrome -->
<meta http-equiv="x-ua-compatible" content="ie=edge,chrome=1">
<!-- 使用 IE9 -->
<meta http-equiv="x-ua-compatible" content="ie=9">
<!-- 若是你須要使用 IE5 的怪異模式 -->
<meta http-equiv="x-ua-compatible" content="ie=5">
|
怪異模式與標準模式
- 怪異模式使用不一樣於標準的盒模型(也就至關於 IE8+ 下的:
box-sizing: border-box
)- 怪異模式下某些行內(inline)元素的垂直對齊行爲表現怪異:怪異模式下對齊圖片至包含它們的盒子的下邊框,而 標準模式圖片對其到父盒的 baseline
接近標準模式(有限怪異模式)與標準模式
主要區別即爲上面的第 2 點
JavaScript 負責 JavaScript 代碼的解釋與執行,主流的 JavaScript 引擎有:V八、SpiderMonkey、JavaScriptCore、Chakra。
瀏覽器與引擎詳情見附錄表格。
當咱們點擊一個連接,服務器將 HTML 代碼傳輸到咱們的瀏覽器,瀏覽器在接收到這份 HTML 代碼以後是如何一步步將頁面呈現出來的呢?這裏面瀏覽器須要作哪些工做?如何優化呈現的過程提高 Web 應用質量?
一個頁面的呈現,粗略的說會通過如下這些步驟:
DOM 樹的構建(Parse HTML)
構建 CSSOM 樹(Recaculate Style)
爲何是 Re-caculate Style 呢?這是由於瀏覽器自己有
User Agent StyleSheet
,因此最終的樣式是咱們的樣式代碼樣式與用戶代理默認樣式覆蓋/從新計算獲得的。
合併 DOM 樹與 CSSOM 樹爲 Render 樹
佈局(Layout)
繪製(Paint)
複合圖層化(Composite)
圖層化是本身理解後形象的意譯
其中佈局(Layout)環節主要負責各元素尺寸、位置的計算,繪製(Paint)環節則是繪製頁面像素信息,合成(Composite)環節是多個複合層的合成,最終合成的頁面被用戶看到。
雖然六部曲看似和諧,分工合做,有序進行。可是實際上這裏面倒是波雲詭譎,風起雲涌,就像平時的工做同樣,看似你和我各司其職,分工明確,可是實際幹起活來卻可能由於某一我的的某一環而阻滯整個進度。
咱們來分析這六部曲中存在的阻塞問題:
當遇到 JavaScript 腳本或者外部 JavaScript 代碼時,瀏覽器便中止 DOM 的構建(阻塞 1)
那是否停下 DOM 的構建的同時,立馬就執行 JavaScript 代碼或者下載外部腳本執行,其實仍是要視狀況而定,見 2
當遇到 <script>
標籤須要執行腳本代碼時,瀏覽器會檢查是否這個 <script>
標籤以上的 CSS 文件是否已經加載並用於構建了 CSSOM,若是 <script>
上部還有 CSS 樣式沒加載,則瀏覽器會等待 <script>
上方樣式的加載完成纔會執行該 <script>
內的腳本(阻塞 2)
DOM 樹與 CSSOM 樹的成功構建是後面步驟的根基(同步阻塞)
同時外部腳本、外部樣式表的下載也是耗費時間較多的點
轉碼(Bytes -> Characters)—— 讀取接收到的 HTML 二進制數據,按指定編碼格式將字節轉換爲 HTML 字符串
Tokens 化(Characters -> Tokens)—— 解析 HTML,將 HTML 字符串轉換爲結構清晰的 Tokens,每一個 Token 都有特殊的含義同時有本身的一套規則
構建 Nodes(Tokens -> Nodes)—— 每一個 Node 都添加特定的屬性(或屬性訪問器),經過指針可以肯定 Node 的父、子、兄弟關係和所屬 treeScope(例如:iframe 的 treeScope 與外層頁面的 treeScope 不一樣)
構建 DOM 樹(Nodes -> DOM Tree)—— 最重要的工做是創建起每一個結點的父子兄弟關係
在 Chrome 開發者工具下 Timeline 面板的
Parse HTML
階段對應着 DOM 樹的構建。
CSSOM 樹的構建 「原料」 的來源有:外部 CSS 文件、內部樣式、內聯樣式。
CSSOM 樹的構建實際上是一個 樣式的從新計算 的過程,爲何是從新計算呢?
用戶代理(即瀏覽器)自己有一套內置樣式表,因此咱們最終的 CSSOM 樹實際上是用戶代理樣式與頁面全部樣式的從新計算。
因此在 Chrome 瀏覽器開發者工具的 Timeline 面板下,CSSOM 樹的構建對應的是
Recalculate Style
階段
與 DOM 樹的構建過程類似,CSSOM 的構建也要經歷如下過程:
DOM 樹與 CSSOM 樹融合成渲染樹
渲染樹只包括渲染頁面須要的節點
排除
<script>
<meta>
等功能化、非視覺節點
排除display: none
的節點
Layout 階段作的工做:肯定頁面各元素的位置、尺寸。
Layout 在 Chrome 開發者工具 Timeline 面板中被歸併到 Paint 階段
當元素某些樣式變動/JavaScript 執行某些樣式請求,會致使 Layout trashing
,又叫作迴流(Reflow)。
一旦佈局(Layout)步驟完成,瀏覽器便觸發 「Paint Setup」 與 「Paint」 事件(渲染引擎底層概念),執行 paint
操做,結合渲染樹與佈局信息繪製實際像素。
注:在 Timeline 工具內,
Layout
與Paint
兩個過程被統一歸併到Paint
階段。
在不少狀況下,咱們不會將複合圖層化納入頁面呈現的必要過程。圖層化是瀏覽器爲了充分利用已有渲染成果(緩存渲染成果),最小化 GPU 運算,將「髒區」提高爲複合圖層,隔離變化影響的操做。
見 連接
知道了頁面渲染的原理,那麼咱們也就獲得了頁面性能優化的依據。提煉六部曲中每一步的優化空間,針對六部曲中的每一步提出針對性的優化方案也就能達到咱們最終的優化目的。
關鍵呈現路徑裏的一些概念:
優化關鍵呈現路徑的指導原則:
優化關鍵呈現路徑常規步驟:
優化關鍵呈現路徑的具體建議:
文件合併、壓縮
推薦使用異步(async
) JavaScript 資源,或使用延遲(defer
)執行的 JavaScript
通常 <script>
腳本的靠後書寫
避免運行時間長的 JavaScript,耗時任務的拆分,chunk 化運行
例如:使用定時器將大任務拆分爲小任務,使得瀏覽器獲得空隙作其餘事情。
避免使用 CSS import
內聯、內部化阻止呈現的 CSS
通常不採用,百度、Google 這樣的極度重視性能與體驗的服務纔可能這樣作。
由於瀏覽器有圖層化這個機制,那麼咱們就搞懂它並充分利用吧。
某些屬性的變動(transform
、opacity
)知足如下條件:
那麼這些屬性變動時就須要一種機制:機制須要能將屬性變動的部分與頁面其餘部分隔離開來,其餘部分已經渲染無缺進行緩存,變動的部分在單獨的圖層上進行,而後對緩存的部分與變動的圖層進行合成。
因此圖層化的關鍵字:緩存、隔離、圖層合成
使用 transform
與 opacity
進行屬性變動是經典的符合圖層化方法,如下是其餘會提高元素爲複合圖層的場景:
translate3d
, translateZ
等等(JS 通常經過這種方式,使元素得到複合圖層)<video>
<iframe>
<canvas>
<webgl>
等元素。opacity
和 transform
作 CSS 動畫。will-change
屬性。position:fixed
。z-index
較低且包含一個複合層的兄弟元素(換句話說就是該元素在複合層上方)很容易看出來:充分利用緩存、隔離的思想,無需像迴流、重繪那麼大性能(GPU、CPU)開支,圖層化能帶來動畫性能的提高。
那麼圖層化的弊端在哪裏呢?
由於圖層化的存在,每一個圖層對須要在內存中存儲該圖層相關的信息,當圖層太多會形成內存開銷過大的狀況(以下圖)。
內存開銷在桌面端可能還能接受,可是在資源有限的移動端,複合圖層過多即可能致使內存開支過大,頁面反而變得停滯、卡頓,甚至瀏覽器假死,系統沒法正常運行。
transfrom
, opacity
background-color
等position
- top
bottom
left
right
width
height
等margin
, padding
, border
JavaScript 存在這樣的機制:當連續有大量 DOM 樣式的操做時,出於性能考慮,防止零碎變動致使頻繁的迴流、重繪,會盡量地將這些操做先緩存起來,而後一次性地變動。這個機制咱們難以察覺可是確實存在。
然而當咱們進行某些 DOM 樣式的讀、寫時,出於時效性的考慮,則會當即觸發瀏覽器迴流、重繪以返回正確、合理的值。
已經比較明白了,那就略吧
也已經比較明白,也略吧
使用 Timeline 工具咱們能作如下事:
而咱們在平常開發中,用 Timeline 最多的場景是:
Timeline 官方簡介
Timeline 事件參考
推薦:Timeline 進行幀分析,避免頁面卡頓
瀏覽器/RunTime | 內核(渲染引擎) | JavaScript 引擎 |
---|---|---|
Chrome | Blink(28~) Webkit(Chrome 27) |
V8 |
FireFox | Gecko | SpiderMonkey |
Safari | Webkit | JavaScriptCore |
Edge | EdgeHTML | Chakra(for JavaScript) |
IE | Trident | Chakra(for JScript) |
PhantomJS | Webkit | JavaScriptCore |
Node.js | - | V8 |