一文摸透從輸入URL到頁面渲染的過程

一文摸透從輸入URL到頁面渲染的過程

從輸入URL到頁面渲染須要Chrome瀏覽器的多個進程配合,因此咱們先來談談現階段Chrome瀏覽器的多進程架構。css

1、Chrome架構

目前Chrome採用的是多進程的架構模式,可分爲主要的五類進程,分別是:瀏覽器(Browser)主進程、 GPU 進程、網絡(NetWork)進程、多個渲染進程和多個插件進程;html

  • 瀏覽器進程。主要負責界面顯示、用戶交互、子進程管理,同時提供存儲等功能。
  • 渲染進程。核心任務是將 HTMLCSSJavaScript 轉換爲用戶能夠與之交互的網頁,排版引擎BlinkJavaScript引擎V8都是運行在該進程中,默認狀況下,Chrome會爲每一個Tab標籤建立一個渲染進程。出於安全考慮,渲染進程都是運行在沙箱模式下。
  • GPU進程。其實,Chrome剛開始發佈的時候是沒有GPU進程的。而GPU的使用初衷是爲了實現3D CSS的效果,只是隨後網頁、ChromeUI界面都選擇採用GPU來繪製,這使得GPU成爲瀏覽器廣泛的需求。最後,Chrome在其多進程架構上也引入了GPU進程。
  • 網絡進程。主要負責頁面的網絡資源加載,以前是做爲一個模塊運行在瀏覽器進程裏面的,直至最近才獨立出來,成爲一個單獨的進程。
  • 插件進程。主要是負責插件的運行,因插件易崩潰,因此須要經過插件進程來隔離,以保證插件進程崩潰不會對瀏覽器和頁面形成影響

瞭解了Chrome的多進程架構,就可以從宏觀上理解從輸入URL到頁面渲染的過程了,這個過程主要分爲導航階段渲染階段webpack

2、導航階段

Ⅰ.瀏覽器主進程

1.用戶輸入URL

  • 一、瀏覽器進程檢查url,組裝協議,構成完整的url,這時候有兩種狀況:
    • 輸入的是搜索內容:地址欄會使用瀏覽器默認的搜索引擎,來合成新的帶搜索關鍵字的URL
    • 輸入的是請求URL:地址欄會根據規則,給這段內容加上協議,合成爲完整的URL
  • 二、瀏覽器進程經過進程間通訊(IPC)把url請求發送給網絡進程;

Ⅱ.網絡進程

2.URL請求過程

  • 三、網絡進程接收到url請求後檢查本地緩存是否緩存了該請求資源,若是有則將該資源返回給瀏覽器進程;

這裏涉及到瀏覽器與HTTP協議的緩存策略問題,有興趣的能夠看這篇文章:詳解HTTP協議web

  • 四、準備IP地址和端口:進行DNS解析時先查找緩存,沒有再使用DNS服務器解析,查找順序爲:chrome

    • 瀏覽器緩存;
    • 本機緩存;
    • hosts文件;
    • 路由器緩存;
    • ISP DNS緩存;
    • DNS遞歸查詢(本地DNS服務器 -> 權限DNS服務器 -> 頂級DNS服務器 -> 13臺根DNS服務器)
  • 五、等待TCP隊列:瀏覽器會爲每一個域名最多維護6TCP鏈接,若是發起一個HTTP請求時,這 6TCP鏈接都處於忙碌狀態,那麼這個請求就會處於排隊狀態;解決方案:瀏覽器

    • 採用域名分片技術:將一個站點的資源放在多個(CDN)域名下面。
    • 升級爲HTTP2,就沒有6TCP鏈接的限制了;
  • 六、經過三次握手創建TCP鏈接:緩存

    123

    • 第一次:客戶端先向服務器端發送一個同步數據包,報文的TCP首部中:標誌位:同步SYN1,表示這是一個請求創建鏈接的數據包;序號Seq=xx爲所傳送數據的第一個字節的序號,隨後進入SYN-SENT狀態;

    標誌位值爲1表示該標誌位有效。安全

    • 第二次:服務器根據收到數據包的SYN標誌位判斷爲創建鏈接的請求,隨後返回一個確認數據包,其中標誌位SYN=1ACK=1,序號seq=y,確認號ack=x + 1表示收到了客戶端傳輸過來的x字節數據,並但願下次從x+1個字節開始傳,並進入SYN-RCVD狀態;

    這裏要區分標誌位ACK和確認號ack服務器

    • 第三次:客戶端收到後,再給服務器發送一個確認數據包,標誌位ACK=1,序號seq=x+1,確認號ack=y+1,隨後進入ESTABLISHED狀態;

    服務器端收到後,也進入ESTABLISHED狀態,由此成功創建了TCP鏈接,能夠開始數據傳送;網絡

    • 爲何要第三次揮手?避免服務器等待形成資源浪費,具體緣由:

    若是沒有最後一個數據包確認(第三次握手),A先發出一個創建鏈接的請求數據包,因爲網絡緣由繞遠路了。A通過設定的超時時間後還未收到B的確認數據包。

    因而發出第二個創建鏈接的請求數據包,此次網路通暢,B的確認數據包也很快就到達A。因而AB開始傳輸數據;

    過了一會A第一次發出的創建鏈接的請求數據包到達了BB覺得是再次創建鏈接,因此又發出一個確認數據包。因爲A已經收到了一個確認數據包,因此會忽略B發來的第二個確認數據包,可是B發出確認數據包以後就要一直等待A的回覆,而A永遠也不會回覆。

    由此形成服務器資源浪費,這種狀況多了B計算機可能就中止響應了。

  • 七、構建併發送HTTP請求信息;

  • 八、服務器端處理請求;

  • 九、客戶端處理響應,首先檢查服務器響應報文的狀態碼:

    • 若是是301/302表示服務器已更換域名須要重定向,這時網絡進程會從響應頭的Location字段裏面讀取重定向的地址,而後再發起新的HTTP或者HTTPS請求,跳回第4步。
    • 若是是200,就檢查Content-Type字段,值爲text/html說明是HTML文檔,是application/octet-stream說明是文件下載;

  • 十、請求結束,當通用首部字段Conection不是Keep-Alive時,即不爲TCP長鏈接時,經過四次揮手斷開TCP鏈接:

  • 第一次:客戶端(主動斷開鏈接)發送數據包給服務器,其中標誌位FIN=1,序號位seq=u,並中止發送數據;
  • 第二次:服務器收到數據包後,因爲還需傳輸數據,沒法當即關閉鏈接,先返回一個標誌位ACK=1,序號seq=v,確認號ack=u+1的數據包;
  • 第三次:服務器準備好斷開鏈接後,返回一個數據包,其中標誌位FIN=1,標誌位ACK=1,序號seq=w,確認號ack=u+1
  • 第四次:客戶端收到數據包後,返回一個標誌位ACK=1,序號seq=u+1,確認號ack=w+1的數據包。

由此經過四次揮手斷開TCP鏈接。

詳細過程參見:詳解TCP鏈接的「三次握手」與「四次揮手」(上)

  • 爲何要四次揮手?因爲服務器不能立刻斷開鏈接,致使FIN釋放鏈接報文與ACK確認接收報文須要分兩次傳輸,即第二次和第三次"揮手";

3.準備渲染進程

  • 十一、準備渲染進程:瀏覽器進程檢查當前url是否與以前打開了渲染進程的頁面的根域名相同,若是相同,則複用原來的進程,若是不一樣,則開啓新的渲染進程;

4.提交文檔

  • 十二、提交文檔:
    • 渲染進程準備好後,瀏覽器渲染進程發起「提交文檔」的消息,渲染進程接收到消息後與網絡進程創建傳輸數據的「管道
    • 渲染進程接收完數據後,向瀏覽器發送「確認提交
    • 瀏覽器進程接收到確認消息後更新瀏覽器界面狀態:安全狀態地址欄url前進後退的歷史狀態更新web頁面

3、渲染階段

在渲染階段經過渲染流水線在渲染進程的主線程和合成線程配合下,完成頁面的渲染;

Ⅲ.渲染進程

渲染進程中的主線程部分

5.構建DOM

  • 1三、先將請求回來的數據解壓,隨後HTML解析器將其中的HTML字節流經過分詞器拆分爲一個個Token,而後生成節點Node,最後解析成瀏覽器識別的DOM樹結構。

    能夠經過Chrome調試工具的Console選項打開控制檯輸入document查看DOM樹;

渲染引擎還有一個安全檢查模塊XSSAuditor,是用來檢測詞法安全的。在分詞器解析出來 Token 以後,它會檢測這些模塊是否安全,好比是否引用了外部腳本是否符合 CSP 規範是否存在跨站點請求等。若是出現不符合規範的內容,XSSAuditor 會對該腳本或者下載任務進行攔截

首次解析HTML渲染進程會開啓一個預解析線程,遇到HTML文檔中內嵌的JavaScriptCSS外部引用就會同步提早下載這些文件,下載時間以最後下載完的文件爲準。

6.構建CSSOM

  • 1四、CSS解析器將CSS轉換爲瀏覽器能識別的styleSheets也就是CSSOM:能夠經過控制檯輸入document.styleSheets查看;

    這裏要考慮一下阻塞的問題,因爲JavaScript有修改CSSHTML的能力,因此,須要先等到 CSS 文件下載完成並生成 CSSOM,而後再執行 JavaScript 腳本,最後再繼續構建 DOM。因爲這種阻塞,致使了解析白屏

優化方案:

  • 移除jscss的文件下載:經過內聯 JavaScript、內聯 CSS
  • 儘可能減小文件大小:如經過 webpack 等工具移除沒必要要的註釋,並壓縮 js 文件
  • 將不進行DOM操做或CSS樣式修改的 JavaScript 標記上 sync 或者 defer異步引入;
  • 使用媒體查詢屬性:將大的CSS文件拆分紅多個不一樣用途的 CSS 文件,只有在特定的場景下才會加載特定的 CSS 文件。

能夠經過瀏覽器調試工具的Network面板中的DOMContentLoaded查看最後生成DOM樹所需的時間;

image-20200405110720560

7.樣式計算

  • 1五、轉換樣式表中的屬性值,使其標準化。好比將em轉換爲pxcolor轉換爲rgb
  • 1六、計算DOM樹中每一個節點的具體樣式,這裏遵循CSS的繼承和層疊規則;能夠經過Chrome調試工具的Elements選項的Computed查看某一標籤的最終樣式;

image-20200405110849074

8.佈局階段

  • 1七、建立佈局樹,遍歷DOM樹中的全部節點,去掉全部隱藏的節點(好比head,添加了display:none的節點),只在佈局樹中保留可見的節點。

  • 1八、計算佈局樹中節點的座標位置(較複雜,這裏不展開);

9.分層

  • 1九、對佈局樹進行分層,並生成分層樹(Layer Tree),能夠經過Chrome調試工具的Layer選項查看。分層樹中每個節點都直接或間接的屬於一個圖層(若是一個節點沒有對應的層,那麼這個節點就從屬於父節點的圖層)

image-20200405111350260

10.圖層繪製

  • 20、爲每一個圖層生成繪製列表(即繪製指令),並將其提交到合成線程。以上操做都是在渲染進程中的主線程中進行的,提交到合成線程後就不阻塞主線程了;

渲染進程中的合成線程部分

11.切分圖塊

2一、合成線程將圖層切分紅大小固定的圖塊(256x256或者512x512)而後優先繪製靠近視口的圖塊,這樣就能夠大大加速頁面的顯示速度;

Ⅳ.GPU進程

12.柵格化操做

  • 2二、光柵化線程池中將圖塊轉換成位圖,一般這個過程都會使用GPU來加速生成,使用GPU生成位圖的過程叫快速柵格化,或者GPU柵格化,生成的位圖被保存在GPU內存中。

Ⅴ.瀏覽器主進程

13.合成與顯示

  • 2三、合成:一旦全部圖塊都被光柵化,合成線程就會將它們合成爲一張圖片,並生成一個繪製圖塊的命令——「DrawQuad」,而後將該命令提交給瀏覽器進程。

注意了:合成的過程是在渲染進程的合成線程中完成的,不會影響到渲染進程的主線程執行;

  • 2四、顯示:瀏覽器進程裏面有一個叫viz的組件,用來接收合成線程發過來的DrawQuad命令,而後根據DrawQuad命令,將其頁面內容繪製到內存中,最後再將內存顯示在屏幕上。

到這裏,通過這一系列的階段,編寫好的HTMLCSSJavaScript等文件,通過瀏覽器就會顯示出漂亮的頁面了。

參考資料:瀏覽器工做原理與實踐

相關文章
相關標籤/搜索