本文原創:gaoruixiacss
提起前端性能優化,你們會想到哪些內容呢?html
相信不一樣的人給出的答案不一樣,關於性能優化沒有標準答案,它更像是一個摸索的過程,本篇文章給出從頁面加載的各個過程分析可優化的點前端
下面這張圖是一個頁面從打開到加載完成經歷的各個階段webpack
瀏覽器得到各個階段的時間耗時的APIweb
- Timing標準:window.performance.timing
- Timing2標準: window.performance.getEntriesByType('navigation')[0]。
複製代碼
Timing目前瀏覽器已再也不提供維護支持,Timing2獲取的精度更加準確(比飛秒還精確,爲10的-17次方秒),但兼容性尚且沒有那麼好(主要是iOS11纔開始支持,其餘瀏覽器都基本沒問題了,IE9咱們就讓它見鬼去吧)。在京麥插件性能統計中,咱們優先判斷是否支持後者,除非後者不支持才使用前者。ajax
白屏時間json
從navigatorStart到responseEnd這段時間算做服務器時間
從瀏覽器開始加載頁面到首次出現內容以前的這段時間(從頁面發送一個頁面URL請求出去,到服務器返回這個HTML的文本內容)後端
計算方式
- Timing: performance.timing.responseEnd - performance.timing.navigationStart
- Timing2: performance.getEntriesByType('navigation')[0].responseStart
複製代碼
瀏覽器渲染時間瀏覽器
從responseEnd到loadEventEnd這段時間,包括CSS、JavaScript、Image等資源的加載耗時緩存
計算方式
- Timing: performance.timing.loadEventEnd - performance.timing.responseEnd
- Timing2: performance.getEntriesByType('navigation')[0].loadEventEnd - performance.getEntriesByType('navigation')[0].responseStart
複製代碼
整頁時間
從瀏覽器開始加載頁面到整個頁面加載完畢(最明顯的標識就是移動端瀏覽器進度條讀完了,pc端瀏覽器就是當前頁籤前面的loading消失了)
計算方式
- Timing: performance.timing.loadEventEnd - performance.timing.navigationStart
- Timing2: performance.getEntriesByType('navigation')[0].loadEventEnd
複製代碼
能夠打開瀏覽器控制檯,切換到Performance,點擊刷新按鈕,等頁面加載完成
先了解下獲得html文本內容後頁面的加載渲染流程(以webkit主流程爲例)
渲染流程有四個主要步驟
以上步驟是一個漸進的過程,爲了提升用戶體驗,渲染引擎試圖儘量快的把結果顯示給最終用戶。它不會等到全部HTML都被解析完才建立並佈局渲染樹。它會在從網絡層獲取文檔內容的同時把已經接收到的局部內容先展現出來。
阻塞渲染的因素
沒有js的理想狀況下,html與css會並行解析,分別生成DOM與CSSOM,而後合併成Render Tree,進入Rendering Pipeline; 但若是有js,css加載會阻塞後面js語句的執行,而(同步)js腳本執行會阻塞其後的DOM解析(因此一般會把css放在頭部,js放在body尾)
CSS的阻塞狀況
JS的阻塞狀況
藍色線表明網絡讀取,紅色線表明執行時間,這倆都是針對腳本的;綠色線表明HTML解析
複製代碼
由上能夠得出影響整頁時間的因素
下圖中,在NetWork資源加載瀑布圖中咱們能夠查看是主要是哪些資源卡住了頁面的整頁時間,發送結束時間均可以觀察到。以後再根據哪一個請求是瓶頸,對那個請求進行分析
使用插件pagespeed
首先去安裝,安裝完pagespeed以後,打開你要調試的網頁,打開控制檯的pagespeed,而後點擊左上角的ANALYZE按鈕,開始分析頁面性能狀況
插件Lighthouse相似,這裏不詳細介紹了
對於整頁時間較長的狀況,須要分析具體是在哪一個階段致使整頁時間比較長,能夠從上面整頁時間的說明裏的各個階段去分析
整頁時間主要在dom解析耗時上,這段時間是從HTML開始解析,到JS所有執行完畢,這之中包含了CSS、JS等資源的加載,須要去優化HTML解析這段時間。
從經常使用性能優化指標咱們知道了頁面加載總共分紅下面這幾個階段:
重定向時間 -> DNS緩存查詢時間 -> DNS查詢時間 -> TCP鏈接時間 -> Request請求時間 -> Response請求響應時間 -> DOM解析時間 -> DOM渲染時間 -> Load事件執行時間
下面來看下各階段的優化手段
這個很簡單,就是請求到正確的地址上便可。
常常會出現的狀況是:
https://xx.com/xx
,這樣會致使瀏覽器重定向到https://xx.com/xx/
這個是瀏覽器作的處理,如Chrome瀏覽器對DNS的緩存時間是1分鐘。
這個階段咱們沒法優化。
HTML的請求的DNS查詢時間咱們沒法縮短,但對於裏面的其餘域名的請求,咱們能夠提早進行DNS查詢,減小資源或者接口的請求時間。
在HTMl的頭部head中加上DNS預查詢便可
<link rel="dns-prefetch" href="//example.com">
通常對CDN須要用到的域名作解析便可。如下是CDN的各個域名:
TCP鏈接時間主要在3次握手中,縮短這個時間就是拉近用戶和服務器機房的距離,對於接口的請求這個很難作到,但對於靜態資源的TCP鏈接時間,咱們能夠經過CDN全國節點縮短用戶與服務器之間的距離。
另外,咱們還能夠用HTTP2的keep-alive來保持長鏈接,這個CDN服務器默認是開啓的,對於接口服務器也能夠進行開啓,雖然異步Ajax請求並不影響整頁時間,但能讓用戶早點看到內容,何樂而不爲。
在Request請求中,請求返回的時間取決於服務器的處理時間。
對於先後端耦合的項目或者SSR的項目,由於須要處理邏輯,拿出數據再動態構建HTML文本,以後再將HTML文本返回給瀏覽器,那這段時間主要在於處理邏輯上。
對於先後端分離的項目,由於返回的是一個空的HTML文本,數據都是等JS調用Ajax獲取的,因此HTML的Request請求時間很短。但這樣咱們得處理Ajax請求,它也有Request請求的時間,這個也得看怎麼在服務端進行性能提高。
雖然Ajax請求不計算在整頁時間中,但也別爲了縮短整頁時間而選擇先後端分離,這個並非它的優點所在。用戶關心的是頁面何時加載完,這其中包含數據何時展示,因此別爲了整頁時間的優化而優化,而應該關心用戶體驗,就算是Ajax接口也應該考慮怎麼提高性能。
並且使用先後端分離其實會加長頁面的白屏時間,這個也是一個衡量頁面性能的一個重要指標,白屏時間能夠經過添加骨架屏來優化。
對於靜態資源的請求,通常資源越小,請求越快(也受服務器帶寬的影響)。能夠經過減少靜態資源(JS、CSS、圖片等)請求的大小從而來縮短請求響應時間。
這段時間從服務器響應返回HTML文本,瀏覽器開始按照從上到下的執行順序解析HTML文本,到執行完HTML中的全部JS,這段時間咱們將其稱爲DOM解析時間。因此優化這段時間在於縮短HTML中的CSS文件和JS文件的請求時間和執行時間,以及縮短HTML的解析時間。
能夠從如下幾方面來作
這個時間就在於減小重排(頁面佈局變更)和重繪(頁面從新渲染元素樣式)
減小重排和重繪的手段
這個時間的壓縮就是減小onload回調函數的耗時處理
不少人習慣將事件綁定放在onload事件中,實際上是能夠將其提早,放在尾部JS中直接執行或者DOMContentLoaded事件中,這時候DOM解析完成了,已經能夠獲取到DOM節點了
本文從頁面加載的各個階段分析影響因素,簡單的給出了可優化的方向,具體實施還須要在工做中結合團隊現狀來進行