一、瀏覽器結(jié)構(gòu)(簡化)
1. 用戶界面
展示除標(biāo)簽頁窗口之外的其他用戶界面內(nèi)容
2. 瀏覽器引擎
用于在用戶界面和渲染引擎之間傳遞數(shù)據(jù)
3. 渲染引擎
負(fù)責(zé)渲染用戶請(qǐng)求的頁面內(nèi)容
二、多進(jìn)程瀏覽器(chrome為例)
可大致拆分為
1. 瀏覽器進(jìn)程
2. 緩存進(jìn)程
3. 網(wǎng)絡(luò)進(jìn)程
4. 渲染器進(jìn)程
瀏覽器會(huì)在默認(rèn)情況為每個(gè)標(biāo)簽頁創(chuàng)建一個(gè)進(jìn)程
- Process-per-site-instance(默認(rèn))
訪問不同站點(diǎn)和同一站點(diǎn)的不同頁面都會(huì)創(chuàng)建新的進(jìn)程 - Process-per-site
同一站點(diǎn)使用同一進(jìn)程 - Process-per-tab
一個(gè)tab里的所有站點(diǎn)使用一個(gè)進(jìn)程 - Single process
讓瀏覽器引擎和渲染引擎共用一個(gè)進(jìn)程
5. GPU進(jìn)程
6. 插件進(jìn)程
三、在地址欄輸入內(nèi)容時(shí)瀏覽器內(nèi)部變化
- 輸入網(wǎng)址時(shí)
- UI線程啟動(dòng)一個(gè)網(wǎng)絡(luò)線程請(qǐng)求DNS進(jìn)行域名解析然后連接服務(wù)器獲取數(shù)據(jù)
- 輸入關(guān)鍵字時(shí)
- 使用默認(rèn)搜索引擎查詢
- 檢查站點(diǎn)是不是惡意站點(diǎn)
- 網(wǎng)絡(luò)線程通知UI線程,然后UI線程創(chuàng)建一個(gè)渲染器進(jìn)程渲染頁面
- 瀏覽器進(jìn)程將數(shù)據(jù)傳遞給渲染器進(jìn)程,正式進(jìn)入渲染流程
- 渲染器進(jìn)程的主線程將html進(jìn)行解析,構(gòu)造DOM數(shù)據(jù)結(jié)構(gòu)(html通過Tokeniser標(biāo)記化,通過詞 法分析將輸入的html將解析成多個(gè)標(biāo)記,據(jù)此進(jìn)行DOM樹(以document為節(jié)點(diǎn))構(gòu)造)。構(gòu)造過程中的其他資源如css、圖片等一般不會(huì)阻塞html解析。但遇到script標(biāo)簽會(huì)停止解析,轉(zhuǎn)而加載解析執(zhí)行js
- 解析完后獲得DOM樹,主線程解析css,確定DOM節(jié)點(diǎn)計(jì)算樣式
- 主線程通過遍歷dom和計(jì)算好的樣式生成layout樹(DOM樹節(jié)點(diǎn)不一定與layout樹節(jié)點(diǎn)一一對(duì)應(yīng))
- 主線程遍歷layout樹生成layer樹(圖層樹)并確定繪制順序后,再傳遞給合成器線程
- 合成器線程將圖層?xùn)鸥窕⑶蟹譃樵S多圖塊,再將每個(gè)圖塊發(fā)送給柵格化線程,柵格完后存在GPU內(nèi)存中,結(jié)束后合成器線程收集圖塊信息,據(jù)此生成合成器幀,通過IPC(進(jìn)程間通信)傳給瀏覽器進(jìn)程
- 瀏覽器進(jìn)程將幀傳給GPU,
- GPU渲染到屏幕上
重排和重繪
重排:改變一個(gè)元素的尺寸位置屬性時(shí),會(huì)重新計(jì)算樣式、布局、繪制及以后的所有流程
重繪:改變某個(gè)元素的顏色屬性時(shí)觸發(fā)樣式計(jì)算和繪制
為什么要避免重繪和重排?:都在主線程上運(yùn)行,會(huì)與JS搶占執(zhí)行時(shí)間。當(dāng)頻繁發(fā)生重排和重繪時(shí),JS運(yùn)行時(shí)間較長的話,有可能會(huì)阻塞主線程,導(dǎo)致掉幀(前一幀繪制完成后,在這一幀剩余時(shí)間開始運(yùn)行js,若運(yùn)行到了下一幀的時(shí)間,則影響下一幀的繪制)
優(yōu)化手段:
- 可以通過requestAnimationFrame(),將JS任務(wù)分成更小的任務(wù)塊分到每一幀,在每一幀時(shí)間用完前暫停JS執(zhí)行交還主線程
- 使用transform動(dòng)畫:不在主線程執(zhí)行,而在合成器線程和柵格線程執(zhí)行。不經(jīng)過樣式計(jì)算和布局繪制,節(jié)省運(yùn)算時(shí)間