引言
對於面試常問的從瀏覽器輸入 URL
到頁面展示過程發生了什麼?,我想大家都或多或少能說出一二。但是,其實這個問題很有深度,而你是否回答的有深度,在很大程度上會影響到面試官對你的印象。
並且,網上各種資料都是淺嘗輒止地講解這個過程,經常會出現今天看到這個版本,明天看到另一個版本地情況。所以,這次我們就來深入淺出一下這整個過程~
一、Chrome 多程式架構
首先,在開始講解整個過程前,我們需要認識一下 Chrome
多程式架構。因為,從瀏覽器輸入 URL
到頁面渲染的整個過程都是由 Chrome
架構中的各個程式之間的配合完成。
Chrome
的多程式架構:
- 瀏覽器程式,它負責使用者介面(位址列、選單等等)、子程式的管理(例如,程式間通訊和資料傳遞)、儲存等等
- 渲染程式,它負責將接收到的
HTML
文件和JavaScript
等轉化為使用者介面 - 網路程式,它負責網路資源的請求,例如
HTTP
請求、WebSocket
模組 GPU
(圖形處理器)程式,它負責對UI
介面的展示- 外掛程式,它負責對外掛的管理
二、過程詳解
2.1 解析輸入
發生這個過程的前提,使用者在位址列中輸入了 URL
,而位址列會根據使用者輸入,做出如下判斷:
- 輸入的是非
URL
結構的字串,則會用瀏覽器預設的搜尋引擎搜尋該字串 - 輸入的是
URL
結構字串,則會構建完整的URL
結構,瀏覽器程式會將完整的URL
通過程式間通訊,即IPC
,傳送給網路程式
2.2 請求過程
在網路程式接收到 URL
後,並不是馬上對指定 URL
進行請求。首先,我們需要進行 DNS
解析域名得到對應的 IP
,然後通過 ARP
解析 IP
得到對應的 MAC
(Media Access Control Address
)地址。
域名是我們取代記憶複雜的
IP
的一種解決方案,而IP
地址才是目標在網路中所被分配的節點。MAC
地址是對應目標網路卡所在的固定地址。
1. DNS 解析
而 DNS
解析域名的過程分為以下幾個步驟:
- 詢問瀏覽器
DNS
快取 - 詢問本地作業系統
DNS
快取(即查詢本地host
檔案) - 詢問
ISP
(Internet Service Provider
)網際網路服務提供商(例如電信、移動)的DNS
伺服器 - 詢問根伺服器,這個過程可以進行遞迴和迭代兩種查詢的方式,兩者都是先詢問頂級域名伺服器查詢
2. 通訊過程
首先,建立 TCP
連線,即三次握手過程:
- 客戶端傳送標有
SYN
的資料包,表示我將要傳送請求。 - 服務端傳送標有
SYN/ACK
的資料包,表示我已經收到通知,告知客戶端傳送請求。 - 客戶端傳送標有
ACK
的資料包,表示我要開始傳送請求,準備被接受。
然後,利用 TCP
通道進行資料傳輸:
- 服務端接收到資料包,併傳送確認資料包已收到的訊息到客戶端,不斷重複這個過程
- 客戶端在傳送一個資料包後,未接收到服務端的確定訊息,則重新傳送該資料包,即
TCP
的重發機制 - 當接收完所有的資料包後,接收端會按照
TCP
頭中的需要進行排序,形成完整的資料
最後,斷開 TCP
連線,即四次握手過程:
- 客戶端傳送請求,申請斷開連線,進入等待階段,此時不會傳送資料,但是會繼續接收資料。
- 服務端接收請求後,告知客戶端已明白,此時服務端進入等待狀態,不會再接收資料,但是會繼續傳送資料。
- 客戶端收到後,進入下一階段等待。
- 服務端傳送完剩餘的資料後,告知客戶端可以斷開連線,此時服務端不會傳送和接收資料。
- 客戶端收到後,告知服務端我開始斷開連線。
- 服務端收到後,開始斷開連線。
而這整個過程的客戶端則是網路程式。並且,在資料傳輸的過程還可能會發生的重定向的情況,即當網路程式接收到狀態碼為 3xx 的響應報文,則會根據響應報文首部欄位中的 Location 欄位的值進行重新向,即會重新發起請求
3. 資料處理
當網路程式接收到的響應報文狀態碼,進行相應的操作。例如狀態碼為 200 OK
時,會解析響應報文中的 Content-Type
首部欄位,例如我們這個過程 Content-Type
會出現 application/javascript
、text/css
、text/html
,即對應 Javascript
檔案、CSS
檔案、HTML
檔案。
詳細的
MIME
型別講解可以看 MDN
2.3 建立渲染程式
當前需要渲染 HTML
時,則需要建立渲染程式,用於後期渲染 HTML
。而對於渲染程式,如果是同一站點是可以共享一個渲染程式,例如 a.abc.com
和 c.abc.com
可以共享一個渲染渲染程式。否則,需要重新建立渲染程式
需要注意的是,同站指的是頂級域名和二級域名相等
2.4 開始渲染
在建立完渲染程式後,網路程式會將接收到的 HTML、JavaScript 等資料傳遞給渲染程式。而在渲染程式接收完資料後,此時使用者介面上會發生這幾件事:
- 更新位址列的安全狀態
- 更新位址列的
URL
- 前進後退此時
enable
,顯示正在載入狀態 - 更新網頁
2.5 渲染過程
大家都知道頁面渲染的過程也是面試中單獨會考的點,並且時常會由這個點延申出另一個問題,即如何避免迴流和重繪。
渲染過程,是整個從理器輸入 URL 到頁面渲染過程的最後一步。而頁面渲染的過程可以分為 9 個步驟:
- 解析
HTML
生成DOM
樹 - 解析
CSS
生成CSSOM
- 載入或執行
JavaScript
- 生成渲染樹(
Render Tree
) - 佈局
- 分層
- 生成繪製列表
- 光柵化
- 顯示
2.5.1 構建 DOM 樹
由於網路程式傳輸給渲染程式的是 HTML
字串,所以,渲染程式需要將 HTML
字串轉化成 DOM
樹。例如:
需要注意的是這個
DOM
樹不同於Chrome-devtool
中Element
選項卡的DOM
樹,它是存在記憶體中的,用於提供JavaScript
對DOM
的操作。
2.5.2 構建 CSSOM
構建 CSSOM
的過程,即通過解析 CSS
檔案、style
標籤、行內 style
等,生成 CSSOM
。而這個過程會做這幾件事:
- 規範
CSS
,即將color: blue
轉化成color: rgb()
形式,可以理解成類似ES6
轉ES5
的過程 - 計算元素樣式,例如
CSS
樣式會繼承父級的樣式,如font-size
、color
之類的。
CSS Object Model
是一組允許用JavaScript
操縱CSS
的API
。詳細API
講解可以看 MDN
2.5.3 載入 JavaScript
通常情況下,在構建 DOM
樹或 CSSOM
的同時,如果也要載入 JavaScript
,則會造成前者的構建的暫停。當然,我們可以通過 defer
或 sync
來實現非同步載入 JavaScript
。雖然 defer
和 sync
都可以實現非同步載入 JavaScript
,但是前者是在載入後,等待 CSSOM
和 DOM
樹構建完後才執行 JavaScript
,而後者是在非同步載入完馬上執行,即使用 sync
的方式仍然會造成阻塞。
而 JavaScript
執行的過程,即編譯和執行 JavaScript
的過程。由於 JavaScript
是解釋型的語言。所以這個過程會是這樣的:
- 針對每句程式碼進行分行處理,即
Token
化 - 根據
Token
,生成AST
(Abstract Sytanx Tree
) 抽象語法樹和建立上下文 - 直譯器解析和執行
AST
,生成位元組碼。 - 編譯器針對需要反覆執行的程式碼,生成對應的機器碼,提高執行效率
2.5.4 生成渲染樹(Render Tree)
在有了 DOM
樹和 CSSOM
之後,需要將兩者結合生成渲染樹 Render Tree
,並且這個過程會去除掉那些 display: node
的節點。此時,渲染樹就具備元素和元素的樣式資訊。
2.5.5 佈局
根據 Render Tree
渲染樹,對樹中每個節點進行計算,確定每個節點在頁面中的寬度、高度和位置。
需要注意的是,第一次確定節點的大小和位置的過程稱為佈局,而第二次才被稱為迴流
2.5.6 分層
由於層疊上下文的存在,渲染引擎會為具備層疊上下文的元素建立對應的圖層,而諸多圖層的疊加就形成了我們看到的一些頁面效果。例如,一些 3D
的效果、動畫就是基於圖層而形成的。
值得一提的是,對於內容溢位存在滾輪的情況也會進行分層
2.5.7 生成繪製列表
對於存在圖層的頁面部分,需要進行有序的繪製,而對於這個過程,渲染引擎會將一個個圖層的繪製拆分成繪製指令,並按照圖層繪製順序形成一個繪製列表。
2.5.8 光柵化
有了繪製列表後,渲染引擎中的合成執行緒會根據當前視口的大小將圖層進行分塊處理,然後合成執行緒會對視口附近的圖塊生成點陣圖,即光柵化。而渲染程式也維護了一個柵格化的執行緒池,專門用於將圖塊轉為點陣圖。
柵格化的過程通常會使用
GPU
加速,例如使用wil-change
、opacity
,就會通過GPU
加速顯示
2.5.9 顯示
當所有的圖塊都經過柵格化處理後,渲染引擎中的合成執行緒會生成繪製圖塊的指令,提交給瀏覽器程式。然後瀏覽器程式將頁面繪製到記憶體中。最後將記憶體繪製結果顯示在使用者介面上。
而這個整個從生成繪製列表、光柵化、顯示的過程,就是我們常說的重繪的過程
結語
整個瀏覽器輸入 URL 到頁面渲染的過程涉及到的知識點非常廣,如 Chrome
多程式的架構、HTTP
通訊過程、瀏覽器解析 JavaScript
過程、瀏覽器繪製頁面過程以及一些計算機的基礎知識等等,並且,這整個過程的分析其實和 Chrome-devtools
密切相關,所以很好的使用 Chrome-devtools
是非常重要的,後續應該會出一篇關於使用 Chrome-devtools
的指南。當然,本篇文章仍然存在諸多不足,歡迎提 issue
~
寫作不易,如果你覺得有收穫的話,可以帥氣三連擊!!!