當咱們在瀏覽器中輸入一個URL後,發生了什麼?

寫在開頭:這篇文章被我納入博客性能優化類別,是由於我認爲若是咱們要優化網站性能、提高用戶體驗,首要目標就是要知道用戶在本地請求並加載你的網頁的過程當中,到底發生了什麼,在此基礎上咱們才能更好的優化網頁。

原文發表在個人我的博客: kmknkk.xincss

圖源:知乎張秋怡
圖源:知乎-張秋怡html

瀏覽器解析並查詢緩存

DNS查詢

  • DNS查詢順序以下,若其中一步成功則直接跳到創建連接部分:canvas

    • 瀏覽器自身DNS
    • 操做系統DNS
    • 本地hosts文件
    • 向域名服務器發送請求

創建連接

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

    • 發送方:SYN(synchronize)
    • 接收方:SYN/ACK(acknowledgement),確認信息傳達
    • 發送方:ACK - 確認接收方在線可收消息,握手結束
    • Accept

TCP三次握手

TCP三次握手的的好處在於:發送方能夠確認接收方仍然在線,不會由於白髮送而浪費資源。緩存

發送HTTP請求

  • 報文首部(GET /index.html HTTP/1.1)性能優化

    • 方法
    • URL
    • HTTP版本
  • 空行(CR+LF)
  • 報文主體

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

從HTTP/1.1開始才默認支持持久化鏈接,即通訊一次之後鏈接不中斷,HTTP/1.0須要手動設置:keep-alive。dom

正常來講,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樹渲染,不可見元素不被會渲染

由DOM樹和CSSOM樹構建Render Tree的過程

  • 佈局(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等。因此在使用中要注意不能濫用,在常觸發重繪和重排的元素上使用便可。