1. 程式人生 > 其它 >從頁面請求到渲染過程的細節

從頁面請求到渲染過程的細節

1.瀏覽器請求頁面到渲染頁面的整個過程

 

  1. 瀏覽器從URL中解析出伺服器的主機名;
  2. 通過域名系統(DNS將主機名轉換成伺服器的IP地址;
  3. 從URL中解析出埠號(如果沒有,http的預設埠號是80,https是443),有了IP地址和埠號就能建立起一條TCP連線
  4. 瀏覽器向伺服器傳送一條HTTP請求報文;
  5. 伺服器向瀏覽器回送一條HTTP響應報文(請求的資源在報文主體中);
  6. 關閉連線,瀏覽器開始渲染頁面;
  7. 瀏覽器將HTML文件解析為DOM樹;
  8. 將CSS檔案解析成StyleSheet物件;
  9. 為每個DOM節點附加(attach)樣式,構建渲染樹;
  10. 佈局(或重排)——遍歷文件元素,計算每個節點在螢幕的位置;
  11. 繪製(或重繪)——遍歷渲染樹,將每個節點繪製到螢幕上,頁面渲染成功。

 

2.域名的解析過程

 

假定域名為m.xyz.com的主機想要訪問y.abc.com,流程如下:

  1. 主機m.xyz.com首先向本地域名伺服器dns.xyz.com查詢。若本地域名伺服器不知道所查詢域名的IP地址,那麼本地域名伺服器將以DNS客戶的身份向其他根域名伺服器繼續發出查詢請求報文(代替主機),而不是主機自己進行下一步的查詢操作(稱為遞迴查詢);
  2. 根域名伺服器並不直接把待查詢的域名直接轉換成IP地址(根域名伺服器也沒有存放這種資訊),而是告訴本地域名伺服器下一步應對向哪一個頂級域名伺服器查詢,也即告訴本地域名伺服器下一次應查詢的頂級域名伺服器dns.com的IP地址;(注意,這裡是讓本地域名伺服器去執行查詢,而沒有像前面那樣,根域名伺服器代替本地域名伺服器去進行下一步查詢,這稱為迭代查詢
  3. 有了這個IP地址,本地域名伺服器就向該頂級域名伺服器dns.com進行查詢。若頂級域名伺服器有y.abc.com的IP地址,則直接返回IP地址;若沒有,則告訴本地域名伺服器下一步應查詢的許可權域名伺服器dns.abc.com的IP地址;(迭代查詢
  4. 本地域名伺服器向許可權域名伺服器dnx.abc.com進行查詢,許可權域名伺服器返回所查詢域名y.abc.com的IP地址;
  5. 本地域名伺服器將最後結果告訴主機。

 

3.TCP連線的三次握手和四次揮手

TCP三次握手建立連線

  1. 最初,客戶端A和伺服器端B都處於 CLOSED(關閉) 狀態。由伺服器端B先進入 LISTEN(收聽) 狀態,等待客戶端的連線;
  2. 第一次握手:客戶端A向伺服器端B發出連線請求報文段,首部的同步位 SYN=1,同時選擇一個初始序列 seq=x,這時客戶端A進入 SYN-SENT(同步已傳送) 狀態;
  3. 第二次握手:伺服器端B收到連線請求報文段後,如同意連線則向A傳送確認。確認報文段中,SYN=1,ACK=1,確認號 ack=x+1,同時為自己選擇一個初始序列 seq=y,伺服器端B進入 SYN-RCVD(同步收到) 狀態;
  4. 第三次握手:客戶端A收到來自伺服器端B的確認後,需要再次傳送確認報文段,ACK=1,確認號 ack=y+1,序號seq=x+1。客戶端A進入 ESTABLISHED(已建立連線) 狀態;
  5. 當伺服器端B收到來自A的確認報文段時,也進入 ESTABLISHED 狀態,此時可以進行資料傳輸。

 

三次揮手中,為什麼A最後還要傳送一次確認?(為什麼要使用三次揮手?)

  目的是防止已失效的連線請求報文由傳送到了B,使得B誤以為A發出了新的連線請求,從而向A傳送確認。假設不使用三次握手,那麼在B看來這裡有兩條TCP連線在進行,但在A看來自己並沒有發出新的連線請求,故不會向新的連線傳輸資料,而B的第二條TCP連線則一直在等待A傳輸資料,造成資源浪費;

  所謂的“已失效的連線請求”,指的是A發出的第一個連線請求報文段並沒有丟失,但在某些網路節點中滯留了,此時A會進行超時重傳第二個連線請求報文段。然而,過了段時間後,滯留的第一個報文段也到達了B。

  若採用三次握手,B收到失效報文段時會發出第二次確認,但A不會對這次確認進行確認,那麼B就收不到“來自A的屬於失效報文段的確認的確認”,這時B就知道A沒有要求新的連線請求。

 

 TCP四次揮手釋放連線

  1. 第一次揮手:資料傳輸結束後,雙方仍處於 ESTABLISHED 狀態。由客戶端A先發出連線釋放報文段,停止傳輸資料並主動關閉TCP連線(伺服器端B也可以先釋放)。連線釋放報文段中,FIN=1,seq=u(等於A前面已傳輸資料的最後一個位元組的序號加1)。這時,A進入 FIN-WAIT-1(終止等待1) 狀態;
  2. 第二次揮手:伺服器端B收到連線釋放報文段後發出確認,ACK=1,ack=u+1,seq=v(等於B前面已傳輸資料的最後一個位元組的序號加1)。這時B進人 CLOSE-WAIT(關閉等待) 狀態,由A->B這個方向的連線就釋放了,但B->A方向還未關閉,故B要傳輸資料時A仍可接收;
  3. 客戶端A收到B的確認後,進人 FIN-WAIT-2(終止等待2) 狀態,等待伺服器端B發出連線釋放報文段;
  4. 第三次揮手:若B已經沒有要向A傳送的資料,則B向A發出連線釋放報文段,FIN=1,ACK=1,seq=w,ack=u+1(需要重複上次已傳送的確認號),這時B進人LAST-ACK(最後確認)狀態;
  5. 第四次揮手:客戶端A收到B的連線釋放報文段後發出確認,ACK=1,ack=w+1,seq=u+1。這時客戶端進人 TIME-WAIT(時間等待) 狀態,經過計時器設定的 2MSL(MSL稱為最長報文段壽命)後進人 CLOSED 狀態,而伺服器端B收到確認後也進入CLOSED 狀態。

 

為什麼A在TIME-WAIT狀態必須等待2MSL?

  • 為了保證A傳送的最後一個確認報文段能夠到達B。因為確認報文段可能丟失,使得處於LAST-ACK 狀態下的B收不到對FIN+ACK報文段的確認而重傳FIN+ACK報文段,那麼A就能在2MSL時間內收到這個重傳的FIN+ACK報文段,重發一次確認,使得A和B都能進入 CLOSED 狀態。如果A在TIME-WAIT狀態中不等待,而是直接進人CLOSED狀態,那麼A就收不到B重傳的FIN+ACK報文段,B也就無法收到A的確認,從而導致B無法進入CLOSED狀態;
  • 防止已失效的連線請求報文段。因為A傳送完最後一個確認報文段後,在等待的2MSL時間內,本連線產生的所有報文段都會到達壽命,使下一次連線中不會出現舊的連線請求報文段。