超詳細講解頁面加載過程

經典面試題:從輸入URL到頁面加載完成之間的過程。你會發現,這題不論大廠小廠,都會問,爲什麼?

因爲它不僅可以考察面試者的知識廣度還能考察面試者的知識深度。

前言

如果這篇文章有幫助到你,❤️關注+點贊❤️鼓勵一下作者,文章公衆號首發,關注 前端南玖 第一時間獲取最新的文章~

在上一篇文章這些瀏覽器面試題,看看你能回答幾個?,我也提到過這個經典面試題。下面我們一起來看看吧~

說一說從輸入URL到頁面呈現發生了什麼?(知識點)

這個題可以說是面試最常見也是一道可以無限難的題了,一般面試官出這道題就是爲了考察你的前端知識的深度與廣度。

1.瀏覽器接受URL開啓網絡請求線程(涉及到:瀏覽器機制,線程與進程等)

2.開啓網絡線程到發出一個完整的http請求(涉及到:DNS解析,TCP/IP請求,5層網絡協議等)

3.從服務器接收到請求到對應後臺接受到請求(涉及到:負載均衡,安全攔截,後臺內部處理等)

4.後臺與前臺的http交互(涉及到:http頭,響應碼,報文結構,cookie等)

5.緩存問題(涉及到:http強緩存與協商緩存等)(請看上一篇文章這些瀏覽器面試題,看看你能回答幾個?

6.瀏覽器接受到http數據包後的解析流程(涉及到html詞法分析,解析成DOM樹,解析CSS生成CSSOM樹,合併生成render渲染樹。然後layout佈局,painting渲染,複合圖層合成,GPU繪製,等)

在瀏覽器地址欄輸入URL

當我們在瀏覽器地址欄輸入URL地址後,瀏覽器會開一個線程來對我們輸入的URL進行解析處理。

瀏覽器中的各個進程及作用:(多進程)

  • 瀏覽器進程:負責管理標籤頁的創建銷燬以及頁面的顯示,資源下載等。
  • 第三方插件進程:負責管理第三方插件。
  • GPU進程:負責3D繪製與硬件加速(最多一個)。
  • 渲染進程:負責頁面文檔解析(HTML,CSS,JS),執行與渲染。(可以有多個)

DNS域名解析

爲什麼需要DNS域名解析?

因爲我們在瀏覽器中輸入的URL通常是一個域名,並不會直接去輸入IP地址(純粹因爲域名比IP好記),但我們的計算機並不認識域名,它只知道IP,所以就需要這一步操作將域名解析成IP。

URL組成部分

  • protocol:協議頭,比如http,https,ftp等;
  • host:主機域名或者IP地址;
  • port:端口號;
  • path:目錄路徑;
  • query:查詢的參數;
  • hash:#後邊的hash值,用來定位某一個位置。

解析過程

  • 首先會查看瀏覽器DNS緩存,有的話直接使用瀏覽器緩存

  • 沒有的話就查詢計算機本地DNS緩存(localhost)

  • 還沒有就詢問遞歸式DNS服務器(就是網絡提供商,一般這個服務器都會有自己的緩存)

  • 如果依然沒有緩存,那就需要通過 根域名服務器 和 TLD域名服務器 再到對應的 權威DNS服務器 找記錄,並緩存到 遞歸式服務器,然後 遞歸服務器 再將記錄返回給本地

⚠️注意:

DNS解析是非常耗時的,如果頁面中需要解析的域名過多,是非常影響頁面性能的。考慮使用dns與加載或減少DNS解析進行優化。

發送HTTP請求

拿到了IP地址後,就可以發起HTTP請求了。HTTP請求的本質就是TCP/IP的請求構建。建立連接時需要3次握手進行驗證,斷開鏈接也同樣需要4次揮手進行驗證,保證傳輸的可靠性

3次握手

  • 第一次握手:客戶端發送位碼爲 SYN = 1(SYN 標誌位置位),隨機產生初始序列號 Seq = J 的數據包到服務器。服務器由 SYN = 1(置位)知道,客戶端要求建立聯機。
  • 第二次握手:服務器收到請求後要確認聯機信息,向客戶端發送確認號Ack = (客戶端的Seq +1,J+1),SYN = 1,ACK = 1(SYN,ACK 標誌位置位),隨機產生的序列號 Seq = K 的數據包。
  • 第三次握手:客戶端收到後檢查 Ack 是否正確,即第一次發送的 Seq +1(J+1),以及位碼ACK是否爲1。若正確,客戶端會再發送 Ack = (服務器端的Seq+1,K+1),ACK = 1,以及序號Seq爲服務器確認號J 的確認包。服務器收到後確認之前發送的 Seq(K+1) 值與 ACK= 1 (ACK置位)則連接建立成功。

直白理解:

(客戶端:hello,你是server麼?服務端:hello,我是server,你是client麼 客戶端:yes,我是client 建立成功之後,接下來就是正式傳輸數據。)

4次揮手

  • 客戶端發送一個FIN Seq = M(FIN置位,序號爲M)包,用來關閉客戶端到服務器端的數據傳送。
  • 服務器端收到這個FIN,它發回一個ACK,確認序號Ack 爲收到的序號M+1。
  • 服務器端關閉與客戶端的連接,發送一個FIN Seq = N 給客戶端。
  • 客戶端發回ACK 報文確認,確認序號Ack 爲收到的序號N+1。

直白理解:

(主動方:我已經關閉了向你那邊的主動通道了,只能被動接收了 被動方:收到通道關閉的信息 被動方:那我也告訴你,我這邊向你的主動通道也關閉了 主動方:最後收到數據,之後雙方無法通信)

五層網絡協議

1、應用層(DNS,HTTP):DNS解析成IP併發送http請求;

2、傳輸層(TCP,UDP):建立TCP連接(3次握手);

3、網絡層(IP,ARP):IP尋址;

4、數據鏈路層(PPP):封裝成幀;

5、物理層(利用物理介質傳輸比特流):物理傳輸(通過雙絞線,電磁波等各種介質)。

OSI七層框架:物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層、應用層

服務器接收請求做出響應

HTTP 請求到達服務器,服務器進行對應的處理。 最後要把數據傳給瀏覽器,也就是返回網絡響應。

跟請求部分類似,網絡響應具有三個部分:響應行、響應頭和響應體。

響應完成之後怎麼辦?TCP 連接就斷開了嗎?

不一定。這時候要判斷Connection字段, 如果請求頭或響應頭中包含Connection: Keep-Alive
表示建立了持久連接,這樣TCP連接會一直保持,之後請求統一站點的資源會複用這個連接。否則斷開TCP連接, 請求-響應流程結束。

狀態碼

狀態碼是由3位數組成,第一個數字定義了響應的類別,且有五種可能取值:

  • 1xx:指示信息–表示請求已接收,繼續處理。
  • 2xx:成功–表示請求已被成功接收、理解、接受。
  • 3xx:重定向–要完成請求必須進行更進一步的操作。
  • 4xx:客戶端錯誤–請求有語法錯誤或請求無法實現。
  • 5xx:服務器端錯誤–服務器未能實現合法的請求。
    平時遇到比較常見的狀態碼有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500(分別表示什麼請自行查找)。

服務器返回相應文件

請求成功後,服務器會返回相應的網頁,瀏覽器接收到響應成功的報文後便開始下載網頁,至此,網絡通信結束。

瀏覽器解析渲染頁面

瀏覽器在接收到HTML,CSS,JS文件之後,它是如何將頁面渲染在屏幕上的?

解析HTML構建DOM Tree

瀏覽器在拿到服務器返回的網頁之後,首先會根據頂部定義的DTD類型進行對應的解析,解析過程將被交給內部的GUI渲染線程來處理。

DTD(Document Type Definition)文檔類型定義

常見的文檔類型定義

//HTML5文檔定義
<!DOCTYPE html>
//用於XHTML 4.0 的嚴格型 
<!DOCTYPE HTMLPUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
//用於XHTML 4.0 的過渡型 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
//用於XHTML 1.0 的嚴格型 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
//用於XHTML 1.0 的過渡型
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

HTML解釋器的工作就是將網絡或者本地磁盤獲取的HTML網頁或資源從字節流解釋成DOM樹🌲結構

通過上圖可以清楚的瞭解這一過程:首先是字節流,經過解碼之後是字符流,然後通過詞法分析器會被解釋成詞語(Tokens),之後經過語法分析器構建成節點,最後這些節點被組建成一顆 DOM 樹。

對於線程化的解釋器,字符流後的整個解釋、佈局和渲染過程基本會交給一個單獨的渲染線程來管理(不是絕對的)。由於 DOM 樹只能在渲染線程上創建和訪問,所以構建 DOM 樹的過程只能在渲染線程中進行。但是,從字符串到詞語這個階段可以交給單獨的線程來做,Chrome 瀏覽器使用的就是這個思想。在解釋成詞語之後,Webkit 會分批次將結果詞語傳遞迴渲染線程。

這個過程中,如果遇到的節點是 JS 代碼,就會調用 JS引擎 對 JS代碼進行解釋執行,此時由於 JS引擎GUI渲染線程 的互斥,GUI渲染線程 就會被掛起,渲染過程停止,如果 JS 代碼的運行中對DOM樹進行了修改,那麼DOM的構建需要從新開始

如果節點需要依賴其他資源,圖片/CSS等等,就會調用網絡模塊的資源加載器來加載它們,它們是異步的,不會阻塞當前DOM樹的構建

如果遇到的是 JS 資源URL(沒有標記異步),則需要停止當前DOM的構建,直到 JS 的資源加載並被 JS引擎 執行後才繼續構建DOM

解析CSS構建CSSOM Tree

CSS解釋器會將CSS文件解釋成內部表示結構,生成CSS規則樹,這個過程也是和DOM解析類似的,CSS 字節轉換成字符,接着詞法解析與法解析,最後構成 CSS對象模型(CSSOM) 的樹結構

構建渲染樹(Render Tree)

DOM TreeCSSOM Tree都構建完畢後,接着將它們合併成渲染樹(Render Tree)渲染樹 只包含渲染網頁所需的節點,然後用於計算每個可見元素的佈局,並輸出給繪製流程,將像素渲染到屏幕上。

渲染(佈局,繪製,合成)

  • 計算CSS樣式 ;
  • 構建渲染樹 ;
  • 佈局,主要定位座標和大小,是否換行,各種position overflow z-index屬性 ;
  • 繪製,將圖像繪製出來。

這個過程比較複雜,涉及到兩個概念: reflow(迴流)和repain(重繪)。DOM節點中的各個元素都是以盒模型的形式存在,這些都需要瀏覽器去計算其位置和大小等,這個過程稱爲relow;當盒模型的位置,大小以及其他屬性,如顏色,字體,等確定下來之後,瀏覽器便開始繪製內容,這個過程稱爲repain。頁面在首次加載時必然會經歷reflow和repain。reflow和repain過程是非常消耗性能的,尤其是在移動設備上,它會破壞用戶體驗,有時會造成頁面卡頓。所以我們應該儘可能少的減少reflow和repain。

這裏Reflow和Repaint的概念是有區別的:

(1)Reflow:即迴流。一般意味着元素的內容、結構、位置或尺寸發生了變化,需要重新計算樣式和渲染樹。

(2)Repaint:即重繪。意味着元素髮生的改變只是影響了元素的一些外觀之類的時候(例如,背景色,邊框顏色,文字顏色等),此時只需要應用新樣式繪製這個元素就可以了。

迴流的成本開銷要高於重繪,而且一個節點的迴流往往回導致子節點以及同級節點的迴流, 所以優化方案中一般都包括,儘量避免迴流。

迴流一定導致重繪,但重繪不一定會導致迴流

合成(composite)

最後一步合成( composite ),這一步驟瀏覽器會將各層信息發送給GPU,GPU將各層合成,顯示在屏幕上

普通圖層和複合圖層

可以簡單的這樣理解,瀏覽器渲染的圖層一般包含兩大類:普通圖層以及複合圖層

首先,普通文檔流內可以理解爲一個複合圖層(這裏稱爲默認複合層,裏面不管添加多少元素,其實都是在同一個複合圖層中)

其次,absolute佈局(fixed也一樣),雖然可以脫離普通文檔流,但它仍然屬於默認複合層

然後,可以通過硬件加速的方式,聲明一個新的複合圖層,它會單獨分配資源
(當然也會脫離普通文檔流,這樣一來,不管這個複合圖層中怎麼變化,也不會影響默認複合層裏的迴流重繪)

可以簡單理解下:GPU中,各個複合圖層是單獨繪製的,所以互不影響,這也是爲什麼某些場景硬件加速效果一級棒

可以Chrome源碼調試 -> More Tools -> Rendering -> Layer borders中看到,黃色的就是複合圖層信息。

推薦閱讀

這些瀏覽器面試題,看看你能回答幾個?
這一次帶你徹底瞭解前端本地存儲
面試官:說一說前端路由與後端路由的區別
JavaScript之原型與原型鏈
Javascript深入之作用域與閉包
this指向與call,apply,bind

覺得文章不錯,可以點個在看呀_另外歡迎留言交流~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章