性能優(yōu)化調(diào)研系列文章
《前端性能優(yōu)化(上)》 主要說(shuō)明了:
- 為什么要進(jìn)行前端性能優(yōu)化矗蕊?
- 如何衡量前端性能郊楣?
這一篇主要記錄了瀏覽器的加載澎语、渲染過(guò)程的調(diào)研結(jié)果和理解榆综。(待詳細(xì)梳理 提供動(dòng)畫版本)
瀏覽器加載杜恰、渲染過(guò)程
有一道經(jīng)典的前端面試題: 從輸入一個(gè)url到頁(yè)面展示發(fā)生了什么饿序? 涉及到計(jì)算機(jī)網(wǎng)絡(luò)劳澄、操作系統(tǒng)、web等各個(gè)方面,從軟件到硬件柴底,從協(xié)議到實(shí)現(xiàn)婿脸,每一個(gè)點(diǎn)都可以展開(kāi)深入的學(xué)習(xí),所以很考察面試者的綜合能力和某一個(gè)方面的深入掌握程度柄驻。
關(guān)于這部分知識(shí)狐树,可以參考李兵老師的《瀏覽器原理》 課程介紹,下面的內(nèi)容很大一部分 都是引用他的課程內(nèi)容;另外《瀏覽器是如何工作的》也非常深入的介紹了瀏覽器工作的原理鸿脓。
如果你想要有更深入的理解和掌握抑钟,建議你跟著大神一起來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的瀏覽器引擎
不聞不若聞之 聞之不若見(jiàn)之 見(jiàn)之不若知之 知之不若行之 學(xué)至于行而止矣 -- 荀子
瀏覽器架構(gòu)
瀏覽器導(dǎo)航
圖片來(lái)源: 極客時(shí)間
- 瀏覽器主進(jìn)程處理用戶輸入
- 瀏覽器主進(jìn)程 通知網(wǎng)絡(luò)進(jìn)程 發(fā)起真正的請(qǐng)求
- 網(wǎng)絡(luò)進(jìn)程接收到請(qǐng)求頭信息之后 發(fā)送給瀏覽器主進(jìn)程
- 瀏覽器主進(jìn)程 接收到網(wǎng)絡(luò)進(jìn)程發(fā)送的頭消息之后 發(fā)送“提交導(dǎo)航 (CommitNavigation)”消息到渲染進(jìn)程
- 渲染進(jìn)程 收到“提交導(dǎo)航”消息之后,直接和網(wǎng)絡(luò)進(jìn)程建立數(shù)據(jù)管道野哭,接受html數(shù)據(jù)
- 渲染進(jìn)程接收html數(shù)據(jù)完成之后在塔,會(huì)通知瀏覽器主進(jìn)程:確認(rèn)提交
- 主進(jìn)程收到渲染進(jìn)程的“確認(rèn)提交”消息之后,就開(kāi)始更新瀏覽器的狀態(tài):loading虐拓、前進(jìn)心俗、后退、url蓉驹、當(dāng)前頁(yè)面
以上 整個(gè)導(dǎo)航流程就走完了城榛。
瀏覽器渲染流水線
一旦渲染進(jìn)程發(fā)送 “確認(rèn)提交”給瀏覽器主進(jìn)程,就會(huì)開(kāi)始解析頁(yè)面加載子資源态兴。
-
html parsing
圖片來(lái)自google 文檔- 解析html -
生成DOM樹(shù)
圖片來(lái)源 google文檔- 生成DOM樹(shù) 樣式計(jì)算:
Recaculate Style
將樣式信息(來(lái)自內(nèi)聯(lián)樣式狠持、style、link等)轉(zhuǎn)換成styleSheets
瞻润;
Recaculate Style
使用所有通過(guò)css parser
解析得到的style rules
喘垂,包括瀏覽器給出的默認(rèn)樣式,計(jì)算出每一個(gè)DOM元素最終的style
的值绍撞,存儲(chǔ)在ComputedStyle
中正勒。
- 布局階段: 生成
LayoutTree
經(jīng)過(guò)樣式計(jì)算階段之后,DOM-Tree
中的節(jié)點(diǎn)都有了自己的樣式信息傻铣,但是還不知道如何排版章贞,放到哪個(gè)位置。
布局階段非洲,就是確定繪制區(qū)域的位置和大小鸭限,相對(duì)來(lái)說(shuō)也是比較復(fù)雜。- 對(duì)于
block flow
布局來(lái)說(shuō)相對(duì)簡(jiǎn)單两踏,從上往下依次排列就好
block flow -
inline block
inline-block - 其他更復(fù)雜的排版:文字败京、float、flex梦染、table等等
- 對(duì)于
總結(jié)來(lái)說(shuō)赡麦,經(jīng)過(guò)了布局階段之后,就生成了一個(gè)
LayoutTree
layout tree
-
paint
google文檔-繪制- 我們已經(jīng)通過(guò)布局階段,得到了一棵
LayoutTree
隧甚,現(xiàn)在我們已經(jīng)知道了每一個(gè)Layout object
的布局车荔、顯示信息 - 分層 生成圖層數(shù)LayerTree:z-index、3D轉(zhuǎn)換戚扳、 z-index 等會(huì)影響布局對(duì)象的顯示順序(層級(jí))請(qǐng)參考 《層疊上下文》
分層 - 根據(jù)
LayerTree
,產(chǎn)出一個(gè)線性的繪制對(duì)象列表(列表中的每一個(gè)元素存放著繪制的顯示對(duì)象和對(duì)應(yīng)的繪制操作) - 對(duì)于單獨(dú)的一個(gè)
Layout Object
族吻,可能會(huì)包含多個(gè)顯示對(duì)象(Display Item
)(如果你使用過(guò)canvas
來(lái)繪制一些東西或者使用過(guò)一些游戲引擎對(duì)這個(gè)應(yīng)該比較熟悉)
- 我們已經(jīng)通過(guò)布局階段,得到了一棵
輸出的display item list
,會(huì)作為合成線程的輸出
current display item list: [
{
"chunk": "LayoutBlockFlow DIV id='example'
0x1b94c141c0:LayoutBlockFlow DIV id='example':DrawingPaintPhaseSelfBlockBackgroundOnly:0",
"state": "t:0x3e697bca90 c:0x3e697ac8d0 e:0x3e697ac290",
"displayItems": [
{
"index": 0,
"clientDebugName": "InlineTextBox 'hi'",
"id": "0x1605c60410:InlineTextBox 'hi':DrawingPaintPhaseForeground:0",
"visualRect": "401,357 72x20",
"opaque": false,
"record": [
{
"method": "drawTextBlob",
"params": {
"x": 401.5,
"y": 373,
"paint": {
"color": "#FF333333",
"strokeWidth": 0,
"strokeMiter": 4,
"flags": "AntiAlias",
"filterLevel": "Low",
"strokeCap": "Butt",
"strokeJoin": "Miter",
"styleName": "Fill"
}
}
}
]
}
]
}
]
- 光柵化
- 渲染主線程提交 繪制列表給 合成線程帽借;
- 合成線程將圖層劃分為圖塊(256256 或者 512512)
- 合成線程將圖塊提交給 柵格化線程池
- 渲染主進(jìn)程 通過(guò)柵格化線程 發(fā)送圖塊生成位圖的指令發(fā)送給GPU,
- GPU 生成圖塊的位圖超歌,保存在GPU內(nèi)存中
- 一旦所有圖塊都被光柵化 合成線程就會(huì)生成一個(gè)繪制圖塊的命令——“DrawQuad”砍艾,然后將該命令提交給瀏覽器進(jìn)程
- 瀏覽器進(jìn)程里面有一個(gè)叫 viz 的組件,用來(lái)接收合成線程發(fā)過(guò)來(lái)的 DrawQuad 命令巍举,然后根據(jù) DrawQuad 命令脆荷,將其頁(yè)面內(nèi)容繪制到內(nèi)存中,最后再將內(nèi)存顯示在屏幕上
圖片來(lái)源:極客時(shí)間
幾個(gè)關(guān)于渲染流水線的問(wèn)題
待補(bǔ)充示例demo
- CSS 外鏈下載會(huì)阻塞 DOM 的構(gòu)建嗎懊悯?
不會(huì)蜓谋, 參考demo
CSS 外鏈下載會(huì)阻塞 布局樹(shù)的構(gòu)建嗎?
會(huì) 參考demo-
CSS外鏈文件下載會(huì)阻塞后面的js的下載嗎炭分?
不會(huì)桃焕,現(xiàn)代瀏覽器會(huì)在收到html文檔之后預(yù)解析,請(qǐng)求所有的資源
image.png -
CSS外鏈文件下載會(huì)阻塞js的執(zhí)行嗎捧毛?
會(huì)
css的下載阻塞了js的執(zhí)行 js文件的下載和執(zhí)行會(huì)阻塞 DOM樹(shù)的構(gòu)建嗎观堂?
會(huì)