1. DNS域名解析
當(dāng)我們開始在瀏覽器中輸入網(wǎng)址的時(shí)候,瀏覽器其實(shí)就已經(jīng)在智能的匹配可能得 url 了。它會(huì)從歷史記錄,書簽等地方,找到已經(jīng)輸入的字符串可能對應(yīng)的 url ,找到同輸入的地址很匹配的項(xiàng),然后給出智能提示,讓你可以補(bǔ)全 url地址。用戶還沒有按下 enter 鍵, 瀏覽器已經(jīng)開始使用 DNS 預(yù)取技術(shù)解析該域名了。
本地查找是一個(gè)遞歸查找的過程,從瀏覽器緩存中查找->本地的hosts文件查找->找本地DNS解析器緩存查找->本地DNS服務(wù)器查找,這個(gè)過程中任何一步找到了都會(huì)結(jié)束查找流程。
如果本地DNS服務(wù)器無法查詢到,則根據(jù)本地DNS服務(wù)器設(shè)置的轉(zhuǎn)發(fā)器進(jìn)行查詢。若未用轉(zhuǎn)發(fā)模式,則迭代查找過程如下圖

結(jié)合起來的過程,可以用一個(gè)圖表示:

在查找過程中,有以下優(yōu)化點(diǎn):
DNS存在著多級(jí)緩存,從離瀏覽器的距離排序的話,有以下幾種: 瀏覽器緩存,系統(tǒng)緩存,路由器緩存,IPS服務(wù)器緩存,根域名服務(wù)器緩存,頂級(jí)域名服務(wù)器緩存,主域名服務(wù)器緩存。
在域名和 IP 的映射過程中,給了應(yīng)用基于域名做負(fù)載均衡的機(jī)會(huì),可以是簡單的負(fù)載均衡,也可以根據(jù)地址和運(yùn)營商做全局的負(fù)載均衡。
2. 建立TCP連接
首先,判斷是不是https的,如果是,則HTTPS其實(shí)是HTTP + SSL / TLS 兩部分組成,也就是在HTTP上又加了一層處理加密信息的模塊。服務(wù)端和客戶端的信息傳輸都會(huì)通過TLS進(jìn)行加密,所以傳輸?shù)臄?shù)據(jù)都是加密后的數(shù)據(jù)。
進(jìn)行三次握手,建立TCP連接。
??? 1.第一次握手:建立連接??蛻舳税l(fā)送連接請求報(bào)文段,將SYN位置為1,Sequence Number為x;然后,客戶端進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器的確認(rèn);
??? 2.第二次握手:服務(wù)器收到SYN報(bào)文段。服務(wù)器收到客戶端的SYN報(bào)文段,需要對這個(gè)SYN報(bào)文段進(jìn)行確認(rèn),設(shè)置Acknowledgment Number為x+1(Sequence Number+1);同時(shí),自己還要發(fā)送SYN請求信息,將SYN位置為1,SequenceNumber為y;服務(wù)器端將上述所有信息放到一個(gè)報(bào)文段(即SYN+ACK報(bào)文段)中,一并發(fā)送給客戶端,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
3.第三次握手:客戶端收到服務(wù)器的SYN+ACK報(bào)文段。然后將Acknowledgment Number設(shè)置為y+1,向服務(wù)器發(fā)送ACK報(bào)文段,這個(gè)報(bào)文段發(fā)送完畢以后,客戶端和服務(wù)器端都進(jìn)入ESTABLISHED狀態(tài),完成TCP三次握手。
SSL握手過程
4.第一階段 建立安全能力 包括協(xié)議版本 會(huì)話Id 密碼構(gòu)件 壓縮方法和初始隨機(jī)數(shù)
5.第二階段 服務(wù)器發(fā)送證書 密鑰交換數(shù)據(jù)和證書請求,最后發(fā)送請求-相應(yīng)階段的結(jié)束信號(hào)
6.第三階段 如果有證書請求客戶端發(fā)送此證書 之后客戶端發(fā)送密鑰交換數(shù)據(jù) 也可以發(fā)送證書驗(yàn)證消息
7.第四階段 變更密碼構(gòu)件和結(jié)束握手協(xié)議
ACK:此標(biāo)志表示應(yīng)答域有效,就是說前面所說的TCP應(yīng)答號(hào)將會(huì)包含在TCP數(shù)據(jù)包中;有兩個(gè)取值:0和1,為1的時(shí)候表示應(yīng)答域有效,反之為0。TCP協(xié)議規(guī)定,只有ACK=1時(shí)有效,也規(guī)定連接建立后所有發(fā)送的報(bào)文的ACK必須為1。
SYN(SYNchronization):在連接建立時(shí)用來同步序號(hào)。當(dāng)SYN=1而ACK=0時(shí),表明這是一個(gè)連接請求報(bào)文。對方若同意建立連接,則應(yīng)在響應(yīng)報(bào)文中使SYN=1和ACK=1. 因此, SYN置1就表示這是一個(gè)連接請求或連接接受報(bào)文。
FIN(finis)即完,終結(jié)的意思, 用來釋放一個(gè)連接。當(dāng) FIN = 1 時(shí),表明此報(bào)文段的發(fā)送方的數(shù)據(jù)已經(jīng)發(fā)送完畢,并要求釋放連接。
發(fā)送HTTP請求,服務(wù)器處理請求,返回響應(yīng)結(jié)果
TCP連接建立后,瀏覽器就可以利用HTTP/HTTPS協(xié)議向服務(wù)器發(fā)送請求了。服務(wù)器接受到請求,就解析請求頭,如果頭部有緩存相關(guān)信息如if-none-match與if-modified-since,則驗(yàn)證緩存是否有效,若有效則返回狀態(tài)碼為304,若無效則重新返回資源,狀態(tài)碼為200.
這里有發(fā)生的一個(gè)過程是HTTP緩存,是一個(gè)??嫉目键c(diǎn),大致過程如圖:

關(guān)閉TCP連接
第一次分手:主機(jī)1(可以使客戶端,也可以是服務(wù)器端),設(shè)置Sequence Number和Acknowledgment Number,向主機(jī)2發(fā)送一個(gè)FIN報(bào)文段;此時(shí),主機(jī)1進(jìn)入FIN_WAIT_1狀態(tài);這表示主機(jī)1沒有數(shù)據(jù)要發(fā)送給主機(jī)2了;
第二次分手:主機(jī)2收到了主機(jī)1發(fā)送的FIN報(bào)文段,向主機(jī)1回一個(gè)ACK報(bào)文段,Acknowledgment Number為Sequence Number加1;主機(jī)1進(jìn)入FIN_WAIT_2狀態(tài);主機(jī)2告訴主機(jī)1,我"同意"你的關(guān)閉請求;
第三次分手:主機(jī)2向主機(jī)1發(fā)送FIN報(bào)文段,請求關(guān)閉連接,同時(shí)主機(jī)2進(jìn)入LAST_ACK狀態(tài);
第四次分手:主機(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后依然沒有收到回復(fù),則證明Server端已正常關(guān)閉,那好,主機(jī)1也可以關(guān)閉連接了。
瀏覽器渲染
按照渲染的時(shí)間順序,流水線可分為如下幾個(gè)子階段:構(gòu)建 DOM 樹、樣式計(jì)算、布局階段、分層、柵格化和顯示。如圖:

? 1. 渲染進(jìn)程將 HTML 內(nèi)容轉(zhuǎn)換為能夠讀懂DOM 樹結(jié)構(gòu)。
? 2.渲染引擎將 CSS 樣式表轉(zhuǎn)化為瀏覽器可以理解的styleSheets,計(jì)算出 DOM 節(jié)點(diǎn)的樣式。
? 3.創(chuàng)建布局樹,并計(jì)算元素的布局信息。
? 4.對布局樹進(jìn)行分層,并生成分層樹。
? 5.為每個(gè)圖層生成繪制列表,并將其提交到合成線程。合成線程將圖層分圖塊,并柵格化將圖塊轉(zhuǎn)換成位圖。
? 6.合成線程發(fā)送繪制圖塊命令給瀏覽器進(jìn)程。瀏覽器進(jìn)程根據(jù)指令生成頁面,并顯示到顯示器上。
構(gòu)建 DOM 樹
瀏覽器從網(wǎng)絡(luò)或硬盤中獲得HTML字節(jié)數(shù)據(jù)后會(huì)經(jīng)過一個(gè)流程將字節(jié)解析為DOM樹,先將HTML的原始字節(jié)數(shù)據(jù)轉(zhuǎn)換為文件指定編碼的字符,然后瀏覽器會(huì)根據(jù)HTML規(guī)范來將字符串轉(zhuǎn)換成各種令牌標(biāo)簽,如html、body等。最終解析成一個(gè)樹狀的對象模型,就是dom樹。
具體步驟:
??? 1.轉(zhuǎn)碼(Bytes -> Characters)—— 讀取接收到的 HTML 二進(jìn)制數(shù)據(jù),按指定編碼格式將字節(jié)轉(zhuǎn)換為 HTML 字符串
???? 2.Tokens 化(Characters -> Tokens)—— 解析 HTML,將 HTML 字符串轉(zhuǎn)換為結(jié)構(gòu)清晰的 Tokens,每個(gè) Token 都有特殊的含義同時(shí)有自己的一套規(guī)則
構(gòu)建 Nodes(Tokens -> Nodes)—— 每個(gè) Node 都添加特定的屬性(或?qū)傩栽L問器),通過指針能夠確定
???? 3.Node 的父、子、兄弟關(guān)系和所屬 treeScope(例如:iframe 的 treeScope 與外層頁面的 treeScope 不同)
???? 4.構(gòu)建 DOM 樹(Nodes -> DOM Tree)—— 最重要的工作是建立起每個(gè)結(jié)點(diǎn)的父子兄弟關(guān)系
樣式計(jì)算
???? 渲染引擎將 CSS 樣式表轉(zhuǎn)化為瀏覽器可以理解的 styleSheets,計(jì)算出 DOM 節(jié)點(diǎn)的樣式。
???? CSS 樣式來源主要有 3 種,分別是通過 link 引用的外部 CSS 文件、style標(biāo)簽內(nèi)的 CSS、元素的 style 屬性內(nèi)嵌的 CSS。,其樣式計(jì)算過程主要為:
???? CSS 文本中有很多屬性值,如 2em、blue、bold,這些類型數(shù)值不容易被渲染引擎理解,所以需要將所有值轉(zhuǎn)換為渲染引擎容易理解的、標(biāo)準(zhǔn)化的計(jì)算值,這個(gè)過程就是屬性值標(biāo)準(zhǔn)化。處理完成后再處理樣式的繼承和層疊,有些文章將這個(gè)過程稱為CSSOM的構(gòu)建過程。
頁面布局
??? 布局過程,即排除 script、meta 等功能化、非視覺節(jié)點(diǎn),排除 display: none 的節(jié)點(diǎn),計(jì)算元素的位置信息,確定元素的位置,構(gòu)建一棵只包含可見元素布局樹。如圖:

?其中,這個(gè)過程需要注意的是回流和重繪,關(guān)于回流和重繪,詳細(xì)的可以看我另一篇文章《瀏覽器相關(guān)原理》,這里就不說了~
生成分層樹
頁面中有很多復(fù)雜的效果,如一些復(fù)雜的 3D 變換、頁面滾動(dòng),或者使用 z-indexing 做 z 軸排序等,為了更加方便地實(shí)現(xiàn)這些效果,渲染引擎還需要為特定的節(jié)點(diǎn)生成專用的圖層,并生成一棵對應(yīng)的圖層樹(LayerTree),如圖:

如果你熟悉 PS,相信你會(huì)很容易理解圖層的概念,正是這些圖層疊加在一起構(gòu)成了最終的頁面圖像。在瀏覽器中,你可以打開 Chrome 的"開發(fā)者工具",More tools選擇"Layers"標(biāo)簽。渲染引擎給頁面分了很多圖層,這些圖層按照一定順序疊加在一起,就形成了最終的頁面。
柵格化
合成線程會(huì)按照視口附近的圖塊來優(yōu)先生成位圖,實(shí)際生成位圖的操作是由柵格化來執(zhí)行的。所謂柵格化,是指將圖塊轉(zhuǎn)換為位圖。如圖:

通常一個(gè)頁面可能很大,但是用戶只能看到其中的一部分,我們把用戶可以看到的這個(gè)部分叫做視口(viewport)。在有些情況下,有的圖層可以很大,比如有的頁面你使用滾動(dòng)條要滾動(dòng)好久才能滾動(dòng)到底部,但是通過視口,用戶只能看到頁面的很小一部分,所以在這種情況下,要繪制出所有圖層內(nèi)容的話,就會(huì)產(chǎn)生太大的開銷,而且也沒有必要。
顯示
最后,合成線程發(fā)送繪制圖塊命令給瀏覽器進(jìn)程。瀏覽器進(jìn)程根據(jù)指令生成頁面,并顯示到顯示器上,渲染過程完成。
轉(zhuǎn)自鏈接