網頁加載性能優化方法研究

網頁的加載性能是影響用戶體驗的最重要因素,頁面加載時間過長,極有可能會令用戶直接關閉網頁,即便網頁自己的流程和UI等方面優化得再出色,也不會有任何價值。本文將以優化網頁加載性能的角度出發,介紹網頁渲染的過程以及各種資源阻塞網頁渲染的狀況,並給出優化的方向
(本文以Chrome爲主瀏覽器進行討論,其餘瀏覽器可能會存在細微不一樣的狀況,不在本文討論的範圍)css

網頁的渲染過程

五個步驟

想要知道如何優化網頁加載性能,首先得清楚瀏覽器加載一個網頁通過了哪些步驟,才能明白應該從哪些方面着手優化。通常來講,瀏覽器從服務器端獲取到HTML文件後就開始了加載過程,加載網頁的過程包括以下五個步驟:html

  • HTML代碼轉化成DOM,並並行地獲取外部資源(包括HTML中出現的JS、CSS、圖片文件)
  • CSS文件下載完成,CSS代碼轉化成CSSOM(CSS Object Model)
  • 結合DOM和CSSOM,生成一棵渲染樹(包含每一個節點的視覺信息)
  • 生成佈局(Layout):將全部渲染樹的全部節點進行平面合成,該步驟能夠計算出元素在網頁中的位置
  • 繪製(Paint):將網頁內容繪製在屏幕上

在加載過程當中,前三步的耗時主要在於外部資源獲取上,只有CSS資源下載完成才能完成第二第三步,生成渲染樹;然後兩步Layout和Paint較爲耗時,且在網頁渲染過程當中會執行屢次,其中首次Paint的耗時能夠視爲頁面從空白到有內容的時間,減少這部分用時能夠給用戶以網頁加載快的錯覺node

瀏覽器實踐

瀏覽器具有一些工具能夠記錄頁面渲染的過程,進而幫助咱們分析哪些方面的性能還有提高的空間。
以最簡單的HTML結構來熟悉一下Chrome中的Performance工具(以前的名字是timeline)。git

首先咱們打開控制檯,切換到Performance工具,在頁面加載前點擊左上角的圓點,開始錄製,頁面加載完再次點擊,中止錄製,等數據分析完成切換到「Event Log」就能夠開始查看渲染過程了。
圖片描述github

咱們先以最簡單的結構進行分析,如加載下方index.html文件:web

<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>測試瀏覽器渲染</title>
  <link rel="stylesheet" href="./assets/style.css">
</head>
<body>
  <h1>koa by html file</h1>
  <script src="./assets/script.js"></script>
  <img width="300" src="./assets/image.png">
</body>
</html>

分析這個網頁加載狀況,以下截圖所示:
圖片描述segmentfault

(上圖爲渲染五個步驟中的第一步,接收html文件解析並並行請求外部資源)瀏覽器

圖片描述

(上圖爲2, 3和4, 5步,接收到CSS文件後構建渲染樹,進行Layout和首次的Paint)性能優化

圖片描述

(上圖爲Load事件以後的Paint)服務器

接着咱們修改一下node層代碼,令CSS文件返回延遲5s,會獲得以下「Event Log」

圖片描述

(css文件延遲5s後,會發現首次Layout和Paint都延遲到5s以後)

爲了研究JS文件對首次Paint的影響,咱們令JS文件返回延遲5s,CSS和圖片都即時返回,會獲得以下「Event Log」

圖片描述

從上面的分析能夠看出:

  • 外部資源是在開頭並行獲取的,並不是HTML解析到引用行再發請求的;
  • CSS文件加載的速度是影響首次Paint時間的因素,當CSS文件下載完成後才能進行CSSOM和渲染樹的構建,而後纔是Layout和Paint過程;
  • JS文件加載的速度不影響首次Paint時間,即便JS文件自己有修改DOM節點的操做,也只是在JS文件加載完成後再進行一次Layout和Paint;

各種資源阻塞網頁加載的狀況

阻塞網頁加載的狀況,能夠分爲兩種:一種是阻塞HTML解析,即阻塞Event Log中的parse HTML步驟,令HTML結構中止解析;另外一種是阻塞渲染,即阻塞Event Log中的Paint步驟,令已經解析好的HTML結構也沒法顯示到瀏覽器上。

CSS資源

CSS樣式沒法影響DOM結構,但能改變頁面中元素呈現的模樣,因此CSS資源能夠阻塞渲染,但不會阻塞HTML解析。

爲了研究CSS是否會阻塞渲染和解析,咱們依然使用以前的index.html文件,只將style.css延遲5s返回,獲得以下實驗結果:

圖片描述

(解析完HTML以後,就並行發JS、CSS和圖片請求,JS和圖片先接收完成,但沒有觸發首次Paint渲染,而是延遲到css文件接收完成,CSSOM和渲染樹構建完成才觸發了首次Paint,所以CSS資源會阻塞渲染)

相同狀況下,頁面的展現和HTML結構如何呢?請看下方動圖:

圖片描述

(在CSS文件接收完成以前,雖然HTML結構已經解析完成,即Elements中HTML結構已經被解析出來,但頁面是一片空白,說明CSS資源不會阻塞解析,但會阻塞渲染

JS資源

JS腳本會影響DOM結構,也能改變頁面中元素呈現的模樣,因此JS資源既能阻塞渲染又能阻塞HTML解析。

爲了研究JS是否會阻塞渲染和解析,咱們依然使用index.html文件,只將script.js延遲5s返回,獲得以下實驗結果:

圖片描述

(並行發送請求,CSS和圖片資源先加載完,觸發了首次Paint渲染,此時JS文件還沒開始下載,因此JS文件並不會影響頁面的首次渲染)

圖片描述

(延遲了5s後,開始接收JS文件,完成後,再次Paint渲染)

相同狀況下,頁面的展現和HTML結構,請看下方動圖:

圖片描述

(JS開始下載以前,CSS資源已經下載完成,頁面也解析並渲染出一部份內容,這部分是JS文件由script標籤引入以前的內容,而script標籤以後的圖片則需等到JS文件加載完成後才進行解析並渲染出來,所以JS資源會阻塞以後的HTML結構解析和渲染

圖片資源

圖片資源沒法對其餘DOM節點進行操做,因此不會阻塞渲染和HTML解析。

爲了研究圖片資源是否會阻塞渲染和解析,咱們依然使用index.html文件,只將png文件延遲5s返回,獲得以下實驗結果:

圖片描述

(並行發送請求,CSS和JS文件都加載後,完成HTML解析和首次Paint渲染)

圖片描述

(當圖片文件加載完成後,再次渲染)

相同狀況下,頁面的展現和HTML結構,請看下方動圖:

圖片描述

(圖片加載以前,頁面的HTML結構已經解析完成,而且畫面也出如今屏幕上,說明圖片資源不會阻塞HTML的解析和畫面渲染

針對首屏的優化建議

從上面的實驗能夠看出,三種資源中只有CSS文件會影響首次Paint的時間。不管是延遲JS仍是圖片,在CSS文件加載完成後,都能先渲染出已經解析好的HTML內容。因爲在首次Paint以前,頁面是一片空白,因此首次Paint的時間也就至關於首屏時間。

針對首次Paint時間的優化,咱們能夠從如下角度進行考慮:

  • CSS會影響首次Paint的時間,應該儘快加載,所以將其放在head標籤處以保障能在解析完HTML後發出請求;
  • JS不會影響首屏的時間,但因爲JS會阻塞以後的頁面內容的解析與渲染,要避免JS在首屏位置出現,通常將它們放在body的最後,另外,JS會影響總體頁面加載的性能,可使用defer和async轉成非阻塞模式(見參考文獻[6]);
  • 圖片不影響首屏時間,但會影響Load事件的時機(沒有找到合適的參考文獻,待我另起一篇文章補充);

參考文獻

  1. 《js必定要放在底部嗎?》https://segmentfault.com/a/11...
  2. 《聊聊瀏覽器的渲染機制》https://www.jianshu.com/p/c90...
  3. 《網頁性能管理詳解》http://www.ruanyifeng.com/blo...
  4. 《瀏覽器渲染過程與性能優化》https://sylvanassun.github.io...
  5. 《How browsers work》http://taligarsiel.com/Projec...
  6. 《JavaScript阻塞剖析與改善》http://www.cnblogs.com/giggle...
相關文章
相關標籤/搜索