瀏覽器渲染頁(yè)面過(guò)程剖析(當(dāng)用戶在地址欄輸入U(xiǎn)RL點(diǎn)擊回車后。。。)

整體過(guò)程

  1. 用戶輸入U(xiǎn)RL地址

  2. 對(duì)URL地址進(jìn)行DNS域名解析

  3. 建立TCP連接(三次握手)

  4. 瀏覽器發(fā)送HTTP請(qǐng)求報(bào)文

  5. 服務(wù)器返回HTTP響應(yīng)報(bào)文

  6. 關(guān)閉TCP連接(四次揮手)

  7. 瀏覽器解析文檔資源并渲染頁(yè)面

DNS域名解析

為什么需要DNS解析域名為IP地址?

網(wǎng)絡(luò)通訊大部分是基于TCP/IP的,而TCP/IP是基于IP地址的,所以計(jì)算機(jī)在網(wǎng)絡(luò)上進(jìn)行通訊時(shí)只能識(shí)別如“202.96.134.133”之類的IP地址,而不能認(rèn)識(shí)域名。我們無(wú)法記住10個(gè)以上IP地址的網(wǎng)站,所以我們?cè)L問(wèn)網(wǎng)站時(shí),更多的是在瀏覽器地址欄中輸入域名,就能看到所需要的頁(yè)面,這是因?yàn)橛幸粋€(gè)叫“DNS服務(wù)器”的計(jì)算機(jī)自動(dòng)把我們的域名“翻譯”成了相應(yīng)的IP地址,然后調(diào)出IP地址所對(duì)應(yīng)的網(wǎng)頁(yè)。

DNS了解一下

DNS( Domain Name System)是“域名系統(tǒng)”的英文縮寫(xiě),是一種組織成域?qū)哟谓Y(jié)構(gòu)的計(jì)算機(jī)和網(wǎng)絡(luò)服務(wù)命名系統(tǒng),它用于TCP/IP網(wǎng)絡(luò),它所提供的服務(wù)是用來(lái)將主機(jī)名和域名轉(zhuǎn)換為IP地址的工作。

DNS解析過(guò)程

瀏覽器收到URL后,先去本地host文件中查找是否有對(duì)應(yīng)的域名IP關(guān)系,如果有即向IP地址發(fā)起請(qǐng)求;如果沒(méi)有,將到DNS服務(wù)器中查找。

DNS分為本地DNS服務(wù)器,根DNS服務(wù)器和各個(gè)子DNS服務(wù)器。

從瀏覽器到本地DNS服務(wù)器屬于遞歸查詢,而DNS服務(wù)器之間屬于迭代查詢。

建立TCP連接

通俗理解

TCP連接就是我們常談的三次握手過(guò)程??

客戶端:“你好在嗎?我要給你發(fā)送東西咯~!”

服務(wù)端:“嗯嗯我在??!你發(fā)吧~”

客戶端: “嗯啊-8-”

圖解

  1. 客戶端發(fā)送連接請(qǐng)求報(bào)文段,將SYN位置為1,Seq為x;然后,客戶端進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器的確認(rèn);
  2. 服務(wù)器收到SYN報(bào)文段。服務(wù)器收到客戶端的SYN報(bào)文段,需要對(duì)這個(gè)SYN報(bào)文段進(jìn)行確認(rèn),設(shè)置ACK為x+1;同時(shí),自己自己還要發(fā)送SYN請(qǐng)求信息,將SYN位置為1,Seq為y;服務(wù)器端將上述所有信息放到一個(gè)報(bào)文段(即SYN+ACK報(bào)文段)中,一并發(fā)送給客戶端,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
  3. 客戶端收到服務(wù)器的SYN+ACK報(bào)文段。然后將ACK設(shè)置為y+1,向服務(wù)器發(fā)送ACK報(bào)文段,這個(gè)報(bào)文段發(fā)送完畢以后,客戶端和服務(wù)器端都進(jìn)入ESTABLISHED狀態(tài),完成TCP三次握手。

為什么是三次握手而不是兩次,四次呢?

在謝希仁著《計(jì)算機(jī)網(wǎng)絡(luò)》第四版中講“三次握手”的目的是“為了防止已失效的連接請(qǐng)求報(bào)文段突然又傳送到了服務(wù)端,因而產(chǎn)生錯(cuò)誤”。在另一部經(jīng)典的《計(jì)算機(jī)網(wǎng)絡(luò)》一書(shū)中講“三次握手”的目的是為了解決“網(wǎng)絡(luò)中存在延遲的重復(fù)分組”的問(wèn)題。

在謝希仁著《計(jì)算機(jī)網(wǎng)絡(luò)》書(shū)中同時(shí)舉了一個(gè)例子,如下:

“已失效的連接請(qǐng)求報(bào)文段”的產(chǎn)生在這樣一種情況下:client發(fā)出的第一個(gè)連接請(qǐng)求報(bào)文段并沒(méi)有丟失,而是在某個(gè)網(wǎng)絡(luò)結(jié)點(diǎn)長(zhǎng)時(shí)間的滯留了,以致延誤到連接釋放以后的某個(gè)時(shí)間才到達(dá)server。本來(lái)這是一個(gè)早已失效的報(bào)文段。但server收到此失效的連接請(qǐng)求報(bào)文段后,就誤認(rèn)為是client再次發(fā)出的一個(gè)新的連接請(qǐng)求。于是就向client發(fā)出確認(rèn)報(bào)文段,同意建立連接。假設(shè)不采用“三次握手”,那么只要server發(fā)出確認(rèn),新的連接就建立了。由于現(xiàn)在client并沒(méi)有發(fā)出建立連接的請(qǐng)求,因此不會(huì)理睬server的確認(rèn),也不會(huì)向server發(fā)送數(shù)據(jù)。但server卻以為新的運(yùn)輸連接已經(jīng)建立,并一直等待client發(fā)來(lái)數(shù)據(jù)。這樣,server的很多資源就白白浪費(fèi)掉了。采用“三次握手”的辦法可以防止上述現(xiàn)象發(fā)生。例如剛才那種情況,client不會(huì)向server的確認(rèn)發(fā)出確認(rèn)。server由于收不到確認(rèn),就知道client并沒(méi)有要求建立連接?!?/p>

在知乎上有個(gè)生動(dòng)的比喻:

三次握手:
“喂,你聽(tīng)得到嗎?”
“我聽(tīng)得到呀,你聽(tīng)得到我嗎?”
“我能聽(tīng)到你,今天balabala……”

兩次握手:
“喂,你聽(tīng)得到嗎?”
“我聽(tīng)得到呀”
“喂喂,你聽(tīng)得到嗎?”
“草,我聽(tīng)得到呀?。。?!”
“你TM能不能聽(tīng)到我講話?。?!喂!”
“……”

四次握手:
“喂,你聽(tīng)得到嗎?”
“我聽(tīng)得到呀,你聽(tīng)得到我嗎?”
“我能聽(tīng)到你,你能聽(tīng)到我嗎?”
“……不想跟傻逼說(shuō)話”

瀏覽器發(fā)送HTTP請(qǐng)求報(bào)文

(略)

服務(wù)器返回HTTP響應(yīng)報(bào)文

(略)

關(guān)閉TCP連接

通俗理解

TCP連接關(guān)閉時(shí)進(jìn)行四次握手過(guò)程??

客戶端:“你好,我這邊沒(méi)有數(shù)據(jù)要傳了,我要關(guān)閉咯。”

服務(wù)端:“收到~我看一下我這邊有沒(méi)數(shù)據(jù)要傳的?!?/p>

服務(wù)端:“我這邊也沒(méi)有數(shù)據(jù)要傳啦,我們可以關(guān)閉連接咯~”

客戶端:”ojbk~“

圖解

  1. 主機(jī)1(可以使客戶端,也可以是服務(wù)器端),設(shè)置Seq和Ack,向主機(jī)2發(fā)送一個(gè)FIN報(bào)文段;此時(shí),主機(jī)1進(jìn)入FIN_WAIT_1狀態(tài);這表示主機(jī)1沒(méi)有數(shù)據(jù)要發(fā)送給主機(jī)2了;
  2. 主機(jī)2收到了主機(jī)1發(fā)送的FIN報(bào)文段,向主機(jī)1回一個(gè)ACK報(bào)文段,Ack為Seq加1;主機(jī)1進(jìn)入FIN_WAIT_2狀態(tài);主機(jī)2告訴主機(jī)1,我“同意”你的關(guān)閉請(qǐng)求;
  3. 主機(jī)2向主機(jī)1發(fā)送FIN報(bào)文段,請(qǐng)求關(guān)閉連接,同時(shí)主機(jī)2進(jìn)入LAST_ACK狀態(tài);
  4. 主機(jī)1收到主機(jī)2發(fā)送的FIN報(bào)文段,向主機(jī)2發(fā)送ACK報(bào)文段,然后主機(jī)1進(jìn)入TIME_WAIT狀態(tài);主機(jī)2收到主機(jī)1的ACK報(bào)文段以后,就關(guān)閉連接;此時(shí),主機(jī)1等待2MSL后依然沒(méi)有收到回復(fù),則證明Server端已正常關(guān)閉,那好,主機(jī)1也可以關(guān)閉連接了。

瀏覽器解析文檔資源并渲染頁(yè)面

  1. HTML解析出DOM Tree

  2. CSS解析出CSSOM Tree

  3. JavaScript代碼由JavaScript引擎處理

  4. DOM樹(shù)建立后根據(jù)CSS樣式進(jìn)行構(gòu)建內(nèi)部繪圖模型,生成RenderObject樹(shù)

  5. 根據(jù)網(wǎng)頁(yè)層次結(jié)構(gòu)構(gòu)建RenderLayer樹(shù),同時(shí)構(gòu)建虛擬繪圖上下文

  6. 依賴2D和3D圖形庫(kù)渲染成圖像結(jié)果呈現(xiàn)在瀏覽器中(Painting)

我們以webkit內(nèi)核瀏覽器渲染過(guò)程為例

HTML解析

HTML Parser的任務(wù)是將HTML標(biāo)記解析成DOM Tree

CSS解析

CSS Parser將CSS解析成Style Rules,Style Rules也叫CSSOM(CSS Object Model)。
StyleRules也是一個(gè)樹(shù)形結(jié)構(gòu),根據(jù)CSS文件整理出來(lái)的類似DOM Tree的樹(shù)形結(jié)構(gòu)

JavaScript處理

瀏覽器解析文檔,當(dāng)遇到script標(biāo)簽的時(shí)候,會(huì)立即解析腳本,停止解析文檔(因?yàn)镴S可能會(huì)改動(dòng)DOM和CSS,所以繼續(xù)解析會(huì)造成浪費(fèi))。
如果腳本是外部的,會(huì)等待腳本下載完畢,再繼續(xù)解析文檔?,F(xiàn)在可以在script標(biāo)簽上增加屬性 defer或者async。
腳本解析會(huì)將腳本中改變DOM和CSS的地方分別解析出來(lái),追加到DOM Tree和Style Rules上。

布局(回流)

創(chuàng)建渲染樹(shù)后,下一步就是布局(Layout),或者叫回流(reflow,relayout),這個(gè)過(guò)程就是通過(guò)渲染樹(shù)中渲染對(duì)象的信息,計(jì)算出每一個(gè)渲染對(duì)象的位置和尺寸,將其安置在瀏覽器窗口的正確位置,而有些時(shí)候我們會(huì)在文檔布局完成后對(duì)DOM進(jìn)行修改,這時(shí)候可能需要重新進(jìn)行布局,也可稱其為回流,本質(zhì)上還是一個(gè)布局的過(guò)程,每一個(gè)渲染對(duì)象都有一個(gè)布局或者回流方法,實(shí)現(xiàn)其布局或回流。

繪制(重繪)

在繪制階段,系統(tǒng)會(huì)遍歷呈現(xiàn)樹(shù),并調(diào)用呈現(xiàn)器的“paint”方法,將呈現(xiàn)器的內(nèi)容顯示在屏幕上。繪制工作是使用用戶界面基礎(chǔ)組件完成的。
CSS2 規(guī)范定義了繪制流程的順序。繪制的順序其實(shí)就是元素進(jìn)入堆棧樣式上下文的順序。這些堆棧會(huì)從后往前繪制,因此這樣的順序會(huì)影響繪制。塊呈現(xiàn)器的堆棧順序如下:

  1. 背景顏色
  2. 背景圖片
  3. 邊框
  4. 子代
  5. 輪廓

Reflow的成本比Repaint的成本高得多的多。DOM Tree里的每個(gè)結(jié)點(diǎn)都會(huì)有reflow方法,一個(gè)結(jié)點(diǎn)的reflow很有可能導(dǎo)致子結(jié)點(diǎn),甚至父點(diǎn)以及同級(jí)結(jié)點(diǎn)的reflow。在一些高性能的電腦上也許還沒(méi)什么,但是如果reflow發(fā)生在手機(jī)上,那么這個(gè)過(guò)程是非常痛苦和耗電的。 所以,下面這些動(dòng)作有很大可能會(huì)是成本比較高的。

  • 當(dāng)你增加、刪除、修改DOM結(jié)點(diǎn)時(shí),會(huì)導(dǎo)致Reflow或Repaint

  • 當(dāng)你移動(dòng)DOM的位置,或是搞個(gè)動(dòng)畫(huà)的時(shí)候。

  • 當(dāng)你修改CSS樣式的時(shí)候。

  • 當(dāng)你Resize窗口的時(shí)候(移動(dòng)端沒(méi)有這個(gè)問(wèn)題),或是滾動(dòng)的時(shí)候。

  • 當(dāng)你修改網(wǎng)頁(yè)的默認(rèn)字體時(shí)。

  • 注:display:none會(huì)觸發(fā)reflow,而visibility:hidden只會(huì)觸發(fā)repaint,因?yàn)闆](méi)有發(fā)現(xiàn)位置變化。

基本上來(lái)說(shuō),reflow有如下的幾個(gè)原因:

  • Initial。網(wǎng)頁(yè)初始化的時(shí)候。

  • Incremental。一些Javascript在操作DOM Tree時(shí)。

  • Resize。其些元件的尺寸變了。

  • StyleChange。如果CSS的屬性發(fā)生變化了。

  • Dirty。幾個(gè)Incremental的reflow發(fā)生在同一個(gè)frame的子樹(shù)上。

參考文章

DNS原理及其解析過(guò)程

通俗大白話來(lái)理解TCP協(xié)議的三次握手和四次分手

TCP的三次握手四次揮手

瀏覽器渲染頁(yè)面過(guò)程與頁(yè)面優(yōu)化

細(xì)說(shuō)瀏覽器輸入U(xiǎn)RL后發(fā)生了什么

(完)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容