瀏覽器工作原理
查看更多學習筆記:GitHub:LoveEmiliaForever
MDN中文官網
導航
導航是加載 web 頁面的第一步:輸入 URL、點擊一個鏈接、提交表單等等
DNS查詢
導航的第一步是要去尋找頁面資源的位置
例如訪問https://example.com
,如果以前沒有訪問過它,則要向名稱服務器
發起DNS查詢
DNS查詢的目的是期望得到網址所對應服務器的IP地址
第一次請求之后,這個 IP 地址可能會被緩存一段時間
通過主機名加載一個頁面通常僅需要一次 DNS 查詢
但是,如果你的頁面里面有多個不同的網址,例如網絡字體
、網絡圖像
、廣告
等的請求地址分別是不同的網址,那么就要進行多次DNS查詢
DNS 查詢可能存在性能問題,特別是對于移動網絡
移動網絡中每一個 DNS 查詢必須從手機發送到基站,然后到達一個認證的 DNS 服務器
這是一個比較大的等待時間
TCP握手
一旦獲取到服務器 IP 地址,瀏覽器就會通過 TCP三次握手
與服務器建立連接
通過 TCP 首先發送了三個消息進行協商,然后在兩臺電腦之間開始一個 TCP會話
這意味著終端與每臺服務器之間還要來回發送三條消息,而請求尚未發出
TLS協商
對于通過 HTTPS
建立的安全連接,還需要另一次握手,即TLS協商
它會決定使用哪種密碼對通信進行加密,驗證服務器,并在開始實際數據傳輸前建立安全連接
這一過程需要在實際發送內容請求之前進行,再往返服務器五次
響應
建立了和服務器的連接后,瀏覽器將自動發送一個HTTP GET 請求
,以請求初始文件
首字節時間TTFB
是用戶通過點擊鏈接進行請求與收到第一個 HTML 數據包之間的時間
第一個內容分塊通常是 14KB 的數據
擁塞控制/TCP慢啟動
TCP 數據包在傳輸過程中被分成若干段,由于 TCP 保證數據包的順序,因此服務器在發送一定數量的數據包后,必須以 ACK 數據包的形式收到客戶端的確認
- 如果服務器在每個網段后都等待 ACK,則會導致客戶端頻繁發出 ACK
- 如果客戶端無法接收到網段,不停地回應 ACK,服務器將一直重新發送網段
為了找到最合適的網段包含數據量,TCP 慢啟動算法
會逐漸增加傳輸數據量,直到確定最大網絡帶寬,往后它還將根據網絡負載進行動態調整
傳輸段的數量由擁塞窗口CWND
的值控制,該值可初始化為 1、2、4 或 10 MSS(以太網中MSS為1500 bytes),客戶端收到后必須發送 ACK,如ACK正常,則CWND翻倍,如異常,CWND減半
解析
解析
是瀏覽器將通過網絡接收的數據轉換為 DOM 和 CSSOM 的步驟
在瀏覽器收到數據的第一塊時,它就可以開始解析收到的信息
即使請求頁面的 HTML 大于初始的 14KB 數據包,瀏覽器也將開始解析并嘗試根據其擁有的數據進行渲染,但最好在前 14KB 中包含瀏覽器開始渲染頁面所需的所有內容
這 14KB 至少應包含頁面模板(第一次渲染所需的 CSS 和 HTML)
構建DOM樹
DOM 樹描述了文檔的內容,因此處理 HTML 標記并構造 DOM 樹是第一步進行的,如果文檔格式良好,則解析它會簡單而快速,DOM 節點的數量越多,構建 DOM 樹所需的時間就越長
當解析器發現非阻塞資源,例如一張圖片,瀏覽器會請求這些資源并且繼續解析
當遇到一個 CSS 文件時,解析也可以繼續進行
但是對于<script>
標簽(特別是沒有 async 或 defer)會阻塞渲染并停止 HTML 的解析
當 JavaScript 解析和執行順序不重要時,可以添加 async 屬性或 defer 屬性,以減少阻塞
等待獲取 CSS 不會阻塞 HTML,但是它會阻塞 JavaScript,因為JS通常會查改CSS
預加載掃描器
在構建DOM樹時,構建程序會占用主線程,在此時,預加載掃描儀將解析現階段可用的內容并請求高優先級資源,如 CSS、JavaScript 和 web 字體
如此,我們不必等到解析器找到對外部資源的引用來請求它,而是異步進行
構建CSSOM樹
CSSOM和DOM相似,都是樹,不過它們兩是獨立的數據結構
瀏覽器將 CSS 規則轉換為可以理解和使用的樣式映射,它會遍歷CSS規則,并創建節點樹
瀏覽器會從節點的最通用規則開始,通過應用更具體的規則遞歸地優化計算的樣式
構建 CSSOM 非常快,它甚至小于一次DNS查詢的時間
JS編譯
JS 會被解析、編譯、解釋
- 腳本被解析為抽象語法樹
- 將抽象語法樹輸入編譯器,輸出字節碼即進行編譯
- 解釋時,大部分代碼在主線程上進行解釋,但如多線程worker的代碼例外
渲染
渲染步驟包括樣式、布局、繪制,在某些情況下還包括合成
CSSOM 樹和 DOM 樹組合成渲染樹,用于計算每個可見元素的布局,將其繪制到屏幕上
某些情況下,可以將內容提升到它們自己的層并進行合成,通過在 GPU 而不是 CPU 上繪制屏幕的一部分來提高性能,從而釋放主線程
樣式
計算樣式樹或渲染樹的構建從 DOM 樹的根開始,遍歷每個可見節點
應用了 visibility: hidden
的節點會包含在渲染樹中,因為它們會占用空間
而不可見和display:none
的節點都不會被包含在渲染樹中
每個可見節點都應用了 CSSOM 規則,渲染樹包含所有可見節點的內容和計算樣式
,將所有相關樣式與 DOM 樹中的每個可見節點匹配起來,并根據 CSS 級聯,確定每個節點的計算樣式
布局
在渲染樹上運行布局以計算每個節點的幾何體
確定呈現樹中所有節點的寬度、高度和位置,以及確定頁面上每個對象的大小和位置
渲染樹會標識顯示哪些節點及其計算樣式,但不標識每個節點的尺寸或位置
為了確定每個對象的確切大小和位置,瀏覽器會從根開始遍歷渲染樹
由于設備關系,會有很多不同的視區大小(如1080p和720p的屏幕就不一樣)
考慮到視口大小,瀏覽器將確定屏幕上所有不同框的尺寸
以視口的大小為基礎,布局通常從 body 開始,用每個元素的框模型屬性排列所有 body 的子孫元素的尺寸,為不知道其尺寸的替換元素(例如圖像)提供占位符空間
第一次確定節點的大小和位置稱為布局,隨后對節點大小和位置的重新計算稱為回流
假設布局發生在返回圖像之前,一旦知道圖像的尺寸,就會出現回流
繪制
在繪制或光柵化階段,瀏覽器將在布局階段計算的每個框轉換為屏幕上的實際像素
繪畫包括將元素的每個可視部分繪制到屏幕上,瀏覽器會非常快速的完成此項工作
為保障質量,瀏覽器通常以60Hz的速度繪制
繪制可以將布局中的元素分解為多個層,有一些特定的屬性和元素可以實例化一個層(<video>
、<canvas>
、css屬性有opacity
、3d transform
、will-change
的元素)
分層可以提高性能,但它是以內存管理為代價的,因此不應過度使用
合成
當文檔的各個部分以不同的層繪制,相互重疊時,必須進行合成,以確保它們以正確的順序繪制到屏幕上,并正確顯示內容
回流會觸發重新繪制和重新合成
交互
可交互時間TTI
是測量從第一個請求導致 DNS 查詢和 SSL 連接到頁面可交互時所用的時間
可交互是 First Contentful Pain1 之后的時間點,頁面在 50ms 內響應用戶的交互
如果主線程正在解析、編譯和執行 JavaScript,則JS不可用,因此無法及時(小于 50ms)響應用戶交互
首次內容繪制,瀏覽器首次渲染任何可見元素 ??