輸入URL後,發生了什麼

瀏覽器解析並查詢緩存

DNS查詢

  • DNS查詢順序如下,若其中一步成功則直接跳到建立鏈接部分:

    • 瀏覽器自身DNS

    • 操作系統DNS

    • 本地hosts文件

    • 向域名服務器發送請求

建立鏈接

  • TCP三次握手(three-way handshaking)

    • 發送方:SYN(synchronize)

    • 接收方:SYN/ACK(acknowledgement),確認信息傳達

    • 發送方:ACK - 確認接收方在線可收消息,握手結束

    • Accept

TCP三次握手的的好處在於:發送方可以確認接收方仍然在線,不會因爲白髮送而浪費資源。

發送HTTP請求

  • 報文首部(GET /index.html HTTP/1.1)

    • 方法

    • URL

    • HTTP版本

  • 空行(CR+LF)

  • 報文主體

注意:1.HTTP是無連接無狀態的,即HTTP在傳輸完成後就會斷開(HTTP1.1以前),並且不會記錄訪問者的狀態。

從HTTP/1.1開始才支持持久連接,即通信一次以後連接不中斷。

正常來說,HTTP請求、響應方式爲每請求一次就響應一次:

請求1 -> 響應1 -> 請求2 -> 響應2 -> 請求3 -> 響應3

若採用持久連接請求管線化方式:

請求1 -> 請求2 -> 請求3 -> 響應1 -> 響應2 -> 響應3

使用管線化的條件:

  • 服務端需要支持管線化

  • 只有GET和HEAD可以進行管線化,POST請求有所限制

  • 管線化不會影響響應到來的順序

2.關於CR(Carriage Return,回車)和LF(Line Feed,換行)

Dos和Windows採用CR/LF表示下一行UNIX/Linux採用LF表示下一行MAC OS系統則採用CR表示下一行

服務器發送響應

  • 報文首部(HTTP/1.1 200 OK)

    • HTTP版本

    • 響應狀態碼

    • 狀態碼信息

  • 空行(CR+LF)

  • 報文主體

客戶端收到頁面,瀏覽器渲染頁面

執行以下過程:

解析HTML

  • 根據DOCTYPE來確定文檔類型(最常見的就是HTML5,注意如果是HTML4的話有嚴格和寬鬆模式之分)

  • 構建DOM樹(根據HTML構建類似於二叉樹的結構樹)

  • 下載資源

    • CSS - 構建CSSOM樹

    • js - 一般下載後立即執行,會阻塞頁面渲染

瀏覽器渲染

在聊瀏覽器渲染之前,我們先明確一個概念: 事實上,我們看到的頁面並不是直觀所見的一層圖頁,而是由許多DOM元素渲染層(Layers)組成的,如下圖。

頁面的渲染過程

所以一個的頁面的渲染過程由如下幾步構成:

  • 構建渲染樹(Render Tree): 根據DOM和CSSOM樹渲染,不可見元素不被會渲染

  • 佈局(layout): CPU根據渲染樹佈局計算元素的具體位置和大小,轉換成絕對像素,並且根據樣式,分割成多個獨立的渲染層(Layers),將每一層對應到位圖中

  • 繪製(Paint): GPU根據每個渲染層(Layers)的位圖繪製每個點,即像素填充,並且將所以渲染層緩存,如果下次頁面變動但是渲染層沒變就不會觸發重繪。

  • 層級合成(Compositing): 顧名思義,即處理多層渲染層之間的關係,將其合成爲一個完整的頁面。

重繪和重排

重繪(repaint):

  • 元素視覺表現屬性被改變即觸發重繪,如改變visibility,color等,不會影響到dom結構

reflow(重排):

  • 與repaint區別就是:所有影響dom的元素佈局的事件都會觸發重排。同時也會觸發repaint。

  • 這種開銷是非常昂貴的,導致性能下降是必然的,頁面元素越多效果越明顯。

reflow常見情況:

  • 增刪改DOM節點

  • 移動DOM的位置或是動畫顯示(所以儘量用canvas來做動畫)

  • 修改width、display等CSS樣式

  • resize窗口或是滾動的時候

  • 修改網頁默認字體(不建議)

  • display:none會觸發reflow和repaint,而visibility:hidden只會產生repaint

顯而易見,要提高頁面性能,首要目標就是減少重繪重排,具體方法包括但不限於以下幾種:

  • 壓縮DOM深度,以免內層元素改變而導致多個外層都改變。

  • 對於沒用的元素,儘量設置爲display:none,減輕繪製壓力。

  • 在對DOM進行大量元素操作時,我們可以使用利用DocumentFragment對象進行操作,最後再一次性裝載進DOM結構中。

  • 指定img的大小:由於img是內聯元素,所以在加載後會改變寬高,嚴重的會導致整個頁面重排,所以最好在渲染前就設置好其寬高,或者讓其脫離文檔流。

DOM渲染層(Layers)與GPU硬件加速

知道了瀏覽器頁面的渲染合成過程後,我們不難得出一個結論:

如果我們把會發生大量重繪重排的元素提取出來,單獨觸發一個渲染層(Layer),就不會把其他元素一起帶着重繪,這會大大提高頁面性能。

那麼如何觸發渲染層,讓GPU來加速繪製呢?最簡單的方法有以下三種:

will-change: transform;will-change: opacity;transform: translateZ(0);

PS:使用Layers來觸發GPU加速(硬件加速)也會帶來負面影響,如電量損失過快、佔用內存和GPU等。所以在使用中要注意不能濫用,在常觸發重繪和重排的元素上使用即可。