前言、瀏覽器架構(gòu)
Chrome主要使用多進(jìn)程架構(gòu),各個(gè)進(jìn)程互相獨(dú)立,具有各自所負(fù)責(zé)的功能,若要互相通信則采用IPC機(jī)制進(jìn)行通信。
1.瀏覽器主進(jìn)程:主要負(fù)責(zé)主界面顯示,用戶(hù)交互,各個(gè)進(jìn)程管理
2.網(wǎng)絡(luò)進(jìn)程:負(fù)責(zé)網(wǎng)絡(luò)資源下載和與渲染進(jìn)程進(jìn)行資源傳輸
3.渲染進(jìn)程:子資源的加載,頁(yè)面解析
4.GPU進(jìn)程:GPU渲染加速,能夠針對(duì)css的一些屬性進(jìn)行性能優(yōu)化,使用GPU進(jìn)行繪制
5.插件進(jìn)程:管理插件使用和執(zhí)行
1、DNS解析
當(dāng)我們輸入域名例如:www.baidu.com的時(shí)候,瀏覽器會(huì)首先調(diào)用器本地的DNS客戶(hù)端來(lái)解析這個(gè)域名,因?yàn)閔ttp協(xié)議的底層tcp/ip協(xié)議只能夠識(shí)別到ip格式的地址,有了ip地址我們就能正確地識(shí)別到目標(biāo)服務(wù)器并開(kāi)始發(fā)送數(shù)據(jù)。
那么什么是DNS呢,它是域名系統(tǒng)(Domain Name System),負(fù)責(zé)將域名解析成ip地址,由根服務(wù)器,頂級(jí)服務(wù)器,二級(jí)服務(wù)器(權(quán)威DNS服務(wù)器)等組成,分層地逐步地將域名解析出來(lái),那么接下來(lái)說(shuō)下瀏覽器將域名解析成ip的過(guò)程。

瀏覽器會(huì)先查找本地的DNS緩存有沒(méi)該域名記錄,若要?jiǎng)t返回,無(wú)則向系統(tǒng)緩存進(jìn)行查找
若系統(tǒng)緩存有該域名的DNS記錄,則返回,無(wú)則向本地的DNS服務(wù)器查找
本地的DNS可能是你搭建的dns服務(wù)或者路由器提供的服務(wù),在本地的DNS服務(wù)器緩存進(jìn)行查找,無(wú)則向上一層的本地DNS服務(wù)器發(fā)起查詢(xún)
無(wú)本地dns服務(wù)器都沒(méi)有改記錄,則向互聯(lián)網(wǎng)運(yùn)營(yíng)商DNS緩存進(jìn)行查找
互聯(lián)網(wǎng)運(yùn)營(yíng)商也無(wú)該記錄的話則向域名系統(tǒng)服務(wù)器發(fā)起查詢(xún),由根域名服務(wù)器,.com頂級(jí)域名服務(wù)器,.baidu.com二級(jí)域名服務(wù)器來(lái)進(jìn)行遞歸查詢(xún),通常到這里就有該dns記錄并返回ip地址
注:DNS主要基于UDP傳輸層協(xié)議,一次UDP名字服務(wù)器交換可以短到兩個(gè)包:一個(gè)查詢(xún)包、一個(gè)響應(yīng)包。一次TCP交換則至少包含9個(gè)包:三次握手初始化TCP會(huì)話、一個(gè)查詢(xún)包、一個(gè)響應(yīng)包以及四次分手的包交換??紤]到效率原因,TCP連接的開(kāi)銷(xiāo)大,故采用UDP作為DNS的運(yùn)輸層協(xié)議,這也將導(dǎo)致只有13個(gè)根域名服務(wù)器的結(jié)果。(UDP不能保證數(shù)據(jù)傳輸?shù)目煽啃?,也無(wú)法避免接受到重復(fù)數(shù)據(jù)的情況)
2、HTTP連接
收到ip地址后就可以發(fā)送http請(qǐng)求了,http的請(qǐng)求報(bào)文包括狀態(tài)行,請(qǐng)求頭和請(qǐng)求消息報(bào)文,由傳輸層通過(guò)tcp/ip協(xié)議轉(zhuǎn)化成數(shù)據(jù)包,經(jīng)過(guò)網(wǎng)絡(luò)層、鏈路層、物理層后再向上逐層遞交和轉(zhuǎn)化在應(yīng)用層里返回給服務(wù)器,服務(wù)器取得數(shù)據(jù)處理后,發(fā)送響應(yīng)報(bào)文包括狀態(tài)行,響應(yīng)頭和響應(yīng)消息報(bào)文,這樣瀏覽器就獲取到響應(yīng)數(shù)據(jù)。
三次握手
http協(xié)議是基于tcp/ip協(xié)議,而在開(kāi)始數(shù)據(jù)傳輸之前會(huì)先進(jìn)行tcp的通道連接,通過(guò)3次握手來(lái)確定是否連接成功。
- 第一次握手:客戶(hù)端發(fā)送SYN(synchronous建立聯(lián)機(jī))為1,seq(順序號(hào)碼)為隨機(jī)數(shù)x,發(fā)送到服務(wù)端,要求建立連接
- 第二次握手:服務(wù)端接收SYN為1的建立連接請(qǐng)求,便向客戶(hù)端發(fā)送確認(rèn)請(qǐng)求,SYN為1,ACK(acknowledgement 確認(rèn))為1,seq為隨機(jī)數(shù)y,ack(確認(rèn)號(hào)碼)為x+1
- 第三次握手:客戶(hù)端接收到確認(rèn)請(qǐng)求,便會(huì)校驗(yàn)ack是否為x+1,若正確則發(fā)送ACK為1,ack為y+1,至此tcp連接建立成功
四次揮手
數(shù)據(jù)傳輸完成后會(huì)通過(guò)四次揮手來(lái)結(jié)束連接。
- 第一次揮手:客戶(hù)端向服務(wù)器發(fā)送FIN為1,seq為隨機(jī)數(shù)x,表示已經(jīng)沒(méi)任何數(shù)據(jù)發(fā)送了
- 第二次揮手:服務(wù)端接收到客戶(hù)端的FIN包,表示接收到客戶(hù)端關(guān)閉連接的請(qǐng)求,但還沒(méi)完全關(guān)閉,此時(shí)向客戶(hù)端發(fā)送ACK為1,ack為x+1
- 第三次揮手:當(dāng)服務(wù)端做好完全關(guān)閉連接的準(zhǔn)備時(shí),會(huì)再向客戶(hù)端發(fā)送FIN為1,seq為隨機(jī)數(shù)y
- 第四次揮手:客戶(hù)端收到服務(wù)端結(jié)束關(guān)閉的請(qǐng)求后,向服務(wù)端發(fā)送ACK為1,ack為y+1,等待2MSL(2 Maximum Segment Lifetime),若再?zèng)]收到服務(wù)端的響應(yīng),便結(jié)束連接,至此四次揮手連接關(guān)閉
3、頁(yè)面渲染
構(gòu)建DOM樹(shù)
瀏覽器不能夠直接識(shí)別到html的文件,它要首先將html文件轉(zhuǎn)換成一種數(shù)據(jù)結(jié)構(gòu)的類(lèi)型-樹(shù),我們將這個(gè)生成后的類(lèi)似樹(shù)狀結(jié)構(gòu)數(shù)據(jù)稱(chēng)為DOM,每個(gè)元素表示DOM上的一個(gè)節(jié)點(diǎn),瀏覽器遍歷這些節(jié)點(diǎn)渲染成頁(yè)面元素。
構(gòu)建CSS STYLESHEETS
同樣道理,瀏覽器會(huì)將css轉(zhuǎn)換為一種瀏覽器可以理解的結(jié)構(gòu)styleSheets,再與DOM樹(shù)結(jié)合,構(gòu)成了具有樣式的布局樹(shù),對(duì)應(yīng)節(jié)點(diǎn)上會(huì)有相應(yīng)的樣式。這里的布局樹(shù)會(huì)去掉隱藏的節(jié)點(diǎn),只有真實(shí)顯示的節(jié)點(diǎn)
布局階段
有了布局樹(shù)就可以將元素渲染到頁(yè)面上,樣式的渲染遵循層疊繼承規(guī)則,當(dāng)我們需要修改樣式的時(shí)候,這里面的布局涉及重排和重繪
回流(reflow)(重排)
頁(yè)面重新渲染,重新布局,修改dom的寬高,位置會(huì)觸發(fā)
重繪(repaint): 頁(yè)面重新繪制,例如修改字體顏色,背景等
回流需要重新計(jì)算布局,耗費(fèi)性能,而重繪只是局部更新,性能渲染較小?;亓鞅囟〞?huì)觸發(fā)重繪,而重繪不一定需要回流。
在操作DOM的時(shí)候,我們應(yīng)該盡可能地減少回流和重繪,降低性能損耗
GUI渲染線程
接下來(lái)我們主要分析GUI渲染線程執(zhí)行的詳細(xì)過(guò)程:
1. 解析HTML文件,構(gòu)建DOM樹(shù),同時(shí)瀏覽器主進(jìn)程負(fù)責(zé)下載CSS文件
2. CSS文件下載完成,解析CSS文件成樹(shù)形的數(shù)據(jù)結(jié)構(gòu),然后結(jié)合DOM樹(shù)合并成RenderObject樹(shù)
3. 布局RenderObject樹(shù),負(fù)責(zé)RenderObject樹(shù)中的元素尺寸,位置等計(jì)算
4. 繪制RenderObject樹(shù),繪制頁(yè)面的像素信息
5. 瀏覽器主進(jìn)程將默認(rèn)圖層和復(fù)合圖層交給GPU進(jìn)程,GPU進(jìn)程再將各個(gè)圖層合成(composite),最后顯示出頁(yè)面
注:
- 默認(rèn)圖層指的就是處于普通文檔流的元素;
- 復(fù)合圖層一般指使用動(dòng)畫(huà)執(zhí)行或者
<video><iframe><canvas><webgl>等元素,也可以使用z-index將層級(jí)高的元素變成復(fù)合圖層,使用復(fù)合圖層可以進(jìn)行硬件加速,其原理就是避免了默認(rèn)圖層的重繪和回流,想了解的童鞋可以自行深入研究。
了解GUI渲染線程的執(zhí)行過(guò)程后,我們可以根據(jù)其渲染原理進(jìn)行渲染優(yōu)化:
- 盡可能提前引入css文件,例如在頭部引入css文件;
- 盡可能早加載css文件中引用的資源,例如自定義字體文件,可以使用預(yù)加載,在link標(biāo)簽加入’rel=”preload” as=”font”‘該元素屬性,不然會(huì)造成渲染阻塞
- 在DOM和CSS渲染之后加載js文件,例如在尾部加載js文件,或者使用該元素屬性”defer”和”async”,進(jìn)行js文件異步加載,但是在不同瀏覽器會(huì)有兼容性問(wèn)題。