介紹瀏覽器內核、JavaScript 引擎以及頁面呈現原理等基礎知識,同時根據原理提出頁面呈現優化方案。javascript
瀏覽器內核
瀏覽器內核又叫渲染引擎,主要負責 HTML、CSS 的解析,頁面佈局、渲染與複合層合成。瀏覽器內核的不一樣帶來的主要問題是對 CSS 的支持度與屬性表現差別。css
如今主流的內核有:Blink、Webkit、Gecko、EdgeHTML、Trident,這裏面有幾個須要注意的地方:html
-
Blink 是在 Webkit 的基礎上的改進,是如今對新特性支持度最好的內核java
-
移動端基本上所有是 Webkit 或 Blink 內核(除去 Android 上騰訊家的 X5),這兩個內核對新特性的支持度較高,因此新特性能夠在移動端大展身手。git
-
Trident 是 IE4+ 的內核,一直持續到 IE11,EdgeHTML 是微軟拋棄 IE 後開發的全新內核github
-
更多資料請看附錄表格web
幾種渲染模式
通常現代瀏覽器都會有如下幾種渲染模式:chrome
- 標準模式
- 接近標準模式(又稱有限怪異模式)
- 怪異模式
不一樣渲染模式出現的緣由
在 IE5 與 NS4 那個年代,瀏覽器大戰,標準未立,Web 則在經歷早期快速地發展。canvas
後來標準逐步創建,新標準的規範與之前 IE五、NS4 的實現存在着不可避免的差別差別,可是此時的網絡世界許許多多舊時的頁面正在運行,若是按照新標準的實現來渲染的話會有大量的問題出現。segmentfault
因此此時大部分現代瀏覽器廠商想到了區別性地使用不一樣渲染模式來對待這些 Web 頁面。
而 IE 隨着升級,對現代標準的支持也愈來愈完善,因此 IE 爲了正常渲染舊時頁面,支持咱們指定哪一個版本的 IE 模式來渲染頁面。
總結就是:
- 怪異模式是 IE5 與 NS4 年代遺留問題的回退方案
- 怪異模式在大部分瀏覽器都有部署,而且能在必定的機制下觸發
不一樣渲染模式的觸發
標準未立以前,HTML 文檔是沒有文檔頭的,同時在 HTML5 以前的 HTML4/3 的文檔頭都有各自的特徵,因此在大部分現代瀏覽器下觸發的機制以下:
-
無
DOCTYPE
頭觸發怪異模式 -
DOCTYPE
頭不正確(不是 html)也觸發怪異模式如:
<!DOCTYPE svg>
-
DOCTYPE
頭爲 HTML3 頭觸發怪異模式 -
DOCTYPE
頭爲 HTML4 頭則觸發接近標準模式(或稱有限怪異模式) -
常見的 HTML5 DOCTYPE 聲明則使用標準模式
在 IE 下,除了文檔頭的差別能夠自動觸發渲染模式的選擇,咱們還能手動指定(在 IE8+ 適用)使用哪一個版本的 IE 渲染模式來渲染咱們的頁面(擴展閱讀):
1 |
<!-- 使用當前操做系統已裝的最新的 IE --> |
不一樣渲染模式的表現差別
怪異模式與標準模式
- 怪異模式使用不一樣於標準的盒模型(也就至關於 IE8+ 下的:
box-sizing: border-box
)- 怪異模式下某些行內(inline)元素的垂直對齊行爲表現怪異:怪異模式下對齊圖片至包含它們的盒子的下邊框,而 標準模式圖片對其到父盒的 baseline
接近標準模式(有限怪異模式)與標準模式
主要區別即爲上面的第 2 點
JavaScript 引擎
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 樹的成功構建是後面步驟的根基(同步阻塞)
-
同時外部腳本、外部樣式表的下載也是耗費時間較多的點
六部曲之 DOM 樹的構建
-
轉碼(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 樹的構建。
留意這篇文章的這些點:
- DOM 構建時對 DOCType 處理
- DOCType 的不一樣或漏缺帶來的文檔解析模式(怪異模式、有限怪異模式、標準模式)的影響
- 處理開標籤與閉標籤的壓棧、彈棧處理
- Chromium 對待自定義標籤的處理
- JavaScript 方法查找 DOM 的過程,使用 ID、類名、複雜選擇器查找 DOM 的對比
六部曲之 CSSOM 樹的構建
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 運算,將「髒區」提高爲複合圖層,隔離變化影響的操做。
見 連接
頁面性能優化
知道了頁面渲染的原理,那麼咱們也就獲得了頁面性能優化的依據。提煉六部曲中每一步的優化空間,針對六部曲中的每一步提出針對性的優化方案也就能達到咱們最終的優化目的。
優化不可避免的阻塞:優化關鍵呈現路徑
關鍵呈現路徑裏的一些概念:
- 關鍵資源:可能阻止網頁首次呈現的資源。
- 關鍵路徑長度:即往返過程數量,或提取全部關鍵資源所需的總時間。
- 關鍵字節:實現網頁首次呈現所需的總字節數,是全部關鍵資源的傳輸文件大小總和。 帶有一個 HTML 網頁的首個示例包含一項關鍵資源(HTML 文檔),關鍵路徑長度也與 1 個網絡往返過程(假設文件較小)相等,並且總的關鍵字節數正好是 HTML 文檔自己的傳輸大小。
優化關鍵呈現路徑的指導原則:
- 儘可能減小關鍵資源數量。
- 儘可能減小關鍵字節數。
- 儘可能縮短關鍵路徑的長度。
優化關鍵呈現路徑常規步驟:
- 分析和描述關鍵路徑:資源數量、字節數、長度。
- 儘可能減小關鍵資源數量:刪除相應資源、延遲下載、標記爲異步資源等等。
- 優化剩餘關鍵資源的加載順序:你須要儘早下載全部關鍵資源,以縮短關鍵路徑長度。
- 儘可能減小關鍵字節數,以縮短下載時間(和往返次數)。
優化關鍵呈現路徑的具體建議:
-
文件合併、壓縮
-
推薦使用異步(
async
) JavaScript 資源,或使用延遲(defer
)執行的 JavaScript -
通常
<script>
腳本的靠後書寫 -
避免運行時間長的 JavaScript,耗時任務的拆分,chunk 化運行
例如:使用定時器將大任務拆分爲小任務,使得瀏覽器獲得空隙作其餘事情。
-
避免使用 CSS import
-
內聯、內部化阻止呈現的 CSS
通常不採用,百度、Google 這樣的極度重視性能與體驗的服務纔可能這樣作。
針對複合圖層化的優化
由於瀏覽器有圖層化這個機制,那麼咱們就搞懂它並充分利用吧。
複合圖層化機制
某些屬性的變動(transform
、opacity
)知足如下條件:
- 不影響文檔流。
- 不依賴文檔流。
- 不會形成重繪。
那麼這些屬性變動時就須要一種機制:機制須要能將屬性變動的部分與頁面其餘部分隔離開來,其餘部分已經渲染無缺進行緩存,變動的部分在單獨的圖層上進行,而後對緩存的部分與變動的圖層進行合成。
因此圖層化的關鍵字:緩存、隔離、圖層合成
使用 transform
與 opacity
進行屬性變動是經典的符合圖層化方法,如下是其餘會提高元素爲複合圖層的場景:
- 3d 或透視變換 CSS 屬性,例如
translate3d
,translateZ
等等(JS 通常經過這種方式,使元素得到複合圖層) <video>
<iframe>
<canvas>
<webgl>
等元素。- 混合插件(如flash)。
- 元素自身的
opacity
和transform
作 CSS 動畫。 - 擁有 CSS Filter 的元素。
- 使用
will-change
屬性。 position:fixed
。- 元素有一個
z-index
較低且包含一個複合層的兄弟元素(換句話說就是該元素在複合層上方)
圖層化的優點
很容易看出來:充分利用緩存、隔離的思想,無需像迴流、重繪那麼大性能(GPU、CPU)開支,圖層化能帶來動畫性能的提高。
圖層化的潛在問題 —— 內存開銷
那麼圖層化的弊端在哪裏呢?
由於圖層化的存在,每一個圖層對須要在內存中存儲該圖層相關的信息,當圖層太多會形成內存開銷過大的狀況(以下圖)。
由於開銷,因此節制
內存開銷在桌面端可能還能接受,可是在資源有限的移動端,複合圖層過多即可能致使內存開支過大,頁面反而變得停滯、卡頓,甚至瀏覽器假死,系統沒法正常運行。
針對迴流的優化
-
- CSS3 > JavaScript
- 屬性變動優先考慮順序(性能表現排序)
transfrom
,opacity
background-color
等position
-top
bottom
left
right
width
height
等margin
,padding
,border
-
JavaScript 存在這樣的機制:當連續有大量 DOM 樣式的操做時,出於性能考慮,防止零碎變動致使頻繁的迴流、重繪,會盡量地將這些操做先緩存起來,而後一次性地變動。這個機制咱們難以察覺可是確實存在。
然而當咱們進行某些 DOM 樣式的讀、寫時,出於時效性的考慮,則會當即觸發瀏覽器迴流、重繪以返回正確、合理的值。
其餘優化技巧
節流函數
已經比較明白了,那就略吧 參考
惰性載入函數
也已經比較明白,也略吧 參考
重任務分片多幀
Timeline 工具
使用 Timeline 工具咱們能作如下事:
- 頁面渲染幀率分析,獲得異常幀信息
- 各種文件執行耗時/耗資源分析
- 文件等待 - 下載時間
- 頁面呈現期間的事件列表
- 某個幀/某個事件的詳細信息分析
而咱們在平常開發中,用 Timeline 最多的場景是:
- 編寫動畫,Debug 不流暢的異常幀,針對性優化(見本章擴展閱讀一節)
- 偵測 從新計算樣式、從新佈局、重繪、從新合成 等事件,針對性優化
- 瞭解 JavaScript 函數調用棧以及函數調用帶來的迴流/重繪事件信息
- 查看在某個事件中代碼的執行耗時(點擊上圖 Main 部分,點擊下方常駐 Panel 內與文件相關的可點擊連接)
讓你的 Timeline 調試更強大
擴展閱讀
Timeline 官方簡介
Timeline 事件參考
推薦:Timeline 進行幀分析,避免頁面卡頓
附錄
瀏覽器內核與 JS 引擎一覽
瀏覽器/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 |