前端開發者應該明白的瀏覽器工作原理
作為前端開發,我們平常跟瀏覽器打交道的時間也是最多的。在前端面試中,一個較為經典的問題:在瀏覽器地址中輸入url地址,敲回車,發生了什麼?瀏覽器究竟做了什麼?相信很多人腦海裡都會出現個大概的輪廓,可是一到細化具體的過程就答不上來。那麼,作為前端開發者,應該從哪些方面延伸來回答這個問題呢?
瀏覽器工作流程
對於瀏覽器來說,當在位址列輸入url地址,瀏覽器所做的事情就是把一個url變成一個在螢幕上顯示的網頁,大致的過程是這樣的:

從HTTP請求回來 ,產生流式的資料,DOM的構建、CSS計算、渲染、繪製,都是儘可能的流式處理前一步的產出,不需要等待上一步完全接受才開始處理,所以我們在瀏覽網頁的時候,才會逐步出現頁面。
- 瀏覽器接受url開啟一個網路請求執行緒
- 瀏覽器發出一個完整的http請求
- 伺服器接收請求到後臺接收請求
- 使用http請求請求頁面
- 把請求回來的html程式碼解析成DOM樹
- CSS的視覺化格式模型解析
- 根據CSS屬性對元素進行渲染,得到記憶體中的點陣圖
- 對點陣圖的合成
- 繪製頁面
瀏覽器接受url開啟網路請求執行緒
第一點主要涉及的是瀏覽器的程序、執行緒模型以及JS的執行機制:
多程序的瀏覽器
大多數瀏覽器是多程序的,有一個主控程序,以及每一個tab頁面都會新開一個程序(某些情況下多個tab會合並進程) 程序可能包括主控程序,外掛程序,GPU,tab頁(瀏覽器核心)等等。
- Browser程序:瀏覽器的主程序(負責協調、主控),只有一個
- 第三方外掛程序:每種型別的外掛對應一個程序,僅當使用該外掛時才建立
- GPU程序:最多一個,用於3D繪製
- 瀏覽器渲染程序(核心):預設每個Tab頁面一個程序,互不影響,控制頁面渲染,指令碼執行,事件處理等(有時候會優化,如多個空白tab會合併成一個程序)
多執行緒的瀏覽器核心
每一個tab頁面可以看作是瀏覽器核心程序,然後這個程序是多執行緒的,它有幾大類子執行緒:
- GUI執行緒
- JS引擎執行緒
- 事件觸發執行緒
- 定時器執行緒
- 網路請求執行緒
開啟網路執行緒發出一個完整的http請求
該部分主要包括:dns查詢、tcp/ip請求構建、五層因特網等內容
DNS查詢
如果輸入的是域名,需要進行dns解析成IP,大致流程:
- 如果瀏覽器有快取,直接使用瀏覽器快取,否則使用本機快取,再沒有的話就是用host
- 如果本地沒有,就向dns域名伺服器查詢(當然,中間可能還會經過路由,也有快取等),查詢到對應的IP。
tcp/ip請求
這裡的tcp/ip請求需要了解3次握手規則建立連線以及斷開連線時的四次揮手,可以參考之前的部落格: blog.csdn.net/bangbanggan…
五層因特網協議
其實這個概念挺難記全的,記不全沒關係,但是要有一個整體概念。 其實就是一個概念:從客戶端發出http請求到伺服器接收,中間會經過一系列的流程。 簡括就是:從應用層的傳送http請求,到傳輸層通過三次握手建立tcp/ip連線,再到網路層的ip定址,再到資料鏈路層的封裝成幀,最後到物理層的利用物理介質傳輸。 當然,服務端的接收就是反過來的步驟。 五層因特爾協議棧其實就是: 1.應用層(dns,http) 2.傳輸層(tcp,udp) 建立tcp連線(三次握手) 3.網路層(IP,ARP) IP定址 4.資料鏈路層(PPP) 5.物理層 OSI七層框架: 物理層、 資料鏈路層、 網路層、 傳輸層、 會話層、 表示層、 應用層。 表示層:主要處理兩個通訊系統中交換資訊的表示方式,包括資料格式交換,資料加密與解密,資料壓縮與終端型別轉換等 會話層:它具體管理不同使用者和程序之間的對話,如控制登陸和登出過程
網路通訊HTTP協議
HTTP協議是基於TCP協議出現的,在TCP的基礎上規定了Request-Response的模型,決定了通訊必須由瀏覽器端發起的,首先來了解下HTTP協議的格式:
HTTP協議格式
HTTP協議大致可以分成以下部分:其中path是請求路徑、version是固定的字串,依次介紹下面的每個部分:

HTTP Method 請求方法
在requestline裡面的方法部分,表示HTTP的操作型別,常見的幾種請求方法如下:
- GET:瀏覽器通過地址訪問頁面均屬於get請求
- POST:常見的表單提交
- HEAD :跟get類似,區別在於只返回請求頭
- PUT:表示新增資源
- DELETE:表示刪除資源
- CONNECT: 多用於HTTPS和WebSocket
- OPTIONS
- TRACE
HTTP Status code狀態碼
常見的狀態碼有以下幾種:
- 1xx:臨時迴應
- 2xx:請求成功,如200
- 3xx:請求目標有變化,如301和302表示臨時和永久重定向,304表示客戶端沒有更新內容
- 4xx;請求錯誤,如403無許可權,404訪問的資源不存在
- 5xx:服務端錯誤,如500服務端錯誤,503服務端暫時錯誤等
在前端開發中,最熟悉的系列無非是大家都喜歡的200請求成功的標誌,在面試中,問得較多的是304快取問題和301、302重定向的問題。
HTTP HEAD(HTTP頭)
HTTP頭可以看做是一個鍵值對,在HTTP標準中,Request Header如下圖:

Response Header如下圖:

在實際的開發中,完整的列表可以參考rfc2616標準。
HTTP Request Body
HTTP請求的body主要用於表單的提交,常見的body格式:
- application/json
- application/x-www-form-urlencoded:使用form標籤提交的html請求,預設產生
- multipart/form-data:當有檔案上傳時,使用的格式
HTTPS
HTTPS在HTTP的基礎上增加了兩個作用,一是確定請求的目標服務端身份,二是保證傳輸的資料不會被篡改或者竊聽,該協議使用加密通道來傳輸HTTP內容,所以首先需要與服務端簡歷TLS加密通道。可以在此處檢視詳情: tools.ietf.org/html/rfc281…
HTTP2
HTTP2是HTTP1.1的升級版,有兩大改進:一是支援服務端推送,二是支援TCP連結複用:則使用同一個TCP連結來傳輸多個HTTP請求。詳情見: tools.ietf.org/html/rfc754…
構建DOM樹
當瀏覽器使用HTTP向服務端請求頁面後,那麼如何去解析請求回來的HTML程式碼、構建DOM樹呢?

字元流如何解析成詞
首先瀏覽器讀取獲取的HTML,根據指定的檔案編碼方式如UTF-8轉換為字元流,再將字串轉換為詞Token。那什麼是詞?詞是編譯原理中的最小單元,如標籤開始、屬性、標籤結束、註釋、CDATA節點。Token會標識出當前Token的種類。舉個列子: <p class="a" >hello</p>
這裡就可以拆分成<p(p標籤的開始)、class="a"(屬性)、>(p標籤的結束)、hello(文字)、 </p>
(結束標籤)
構建DOM樹
接下來就是將詞變成DOM樹。在構建DOM樹時,是一邊生成Token一邊消耗Token來生成節點的。
<html> <head> <title>Web page parsing</title> </head> <body> <div> <h1>Web page parsing</h1> <p>This is an example Web page.</p> </div> </body> </html> 複製程式碼
構建的DOM樹:

構建CSSOM
在構建完DOM樹,當前的物件只包含節點和屬性,沒有任何樣式資訊,那麼瀏覽器是如何給DOM樹新增CSS屬性呢?我們知道瀏覽器是流式的處理整個過程,我們拿到DOM樹構造好的元素,依次去檢查他匹配的規則,再根據規則的優先順序,做覆蓋和調整。
構建渲染樹
當CSSOM樹和DOM樹都得到之後,將兩個樹進行合併就得到了渲染樹:
