網頁的加載性能是影響用戶體驗的最重要因素,頁面加載時間過長,極有可能會令用戶直接關閉網頁,即便網頁自己的流程和UI等方面優化得再出色,也不會有任何價值。本文將以優化網頁加載性能的角度出發,介紹網頁渲染的過程以及各種資源阻塞網頁渲染的狀況,並給出優化的方向。
(本文以Chrome爲主瀏覽器進行討論,其餘瀏覽器可能會存在細微不一樣的狀況,不在本文討論的範圍)css
想要知道如何優化網頁加載性能,首先得清楚瀏覽器加載一個網頁通過了哪些步驟,才能明白應該從哪些方面着手優化。通常來講,瀏覽器從服務器端獲取到HTML文件後就開始了加載過程,加載網頁的過程包括以下五個步驟:html
在加載過程當中,前三步的耗時主要在於外部資源獲取上,只有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解析,即阻塞Event Log中的parse HTML步驟,令HTML結構中止解析;另外一種是阻塞渲染,即阻塞Event Log中的Paint步驟,令已經解析好的HTML結構也沒法顯示到瀏覽器上。
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腳本會影響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時間的優化,咱們能夠從如下角度進行考慮: