前端性能優化到底該怎麼做(上)— 開門見山
作者:熊的貓
https://juejin.cn/post/7137058832592666655
前言
前端性能優化 又是個聽起來很高大上的詞,確實是的,因爲它需要 高在性能,大在範圍
,所幸很多大佬都已經輸出了很多高質量的內容供大家參考,作者最近也在學習和了解這方面的內容,對如下文中的一些理解若有不當之處,可在評論區討論!!!
前端性能優化這個內容打算分爲 上下兩篇,本來打算一篇寫完,但發現前置知識部分已經佔了 3000+
文字,因此本篇文章主要還是講解一些必要了解的前置內容。
前端性能優化到底是在優化什麼?
其實前端性能優化核心就是兩點:
-
保證資源更快的 加載速度:達到越快渲染越快,視圖展現就越快
-
保證視圖更快的 渲染速度 / 交互速度:用戶與頁面交互,前提是頁面要渲染出來,其次是頁面需要儘早反饋,目的就是保證用戶良好的體驗性
而這些核心內容都可以從下面這個老生常談的問題中延伸開來。
從輸入
URL
到頁面加載完成發生了什麼?
相信到現在爲止,大家對這個問題的回答可以說是能夠做到滔滔不絕了吧(如果不能,請忽略)!不過每個人回答的方向和重點應該都不一樣,比如之前在 B 站
聽 winter
大佬對這個問題的看法和解析的角度是更深、更廣的。
在這還是要簡單的總結一下核心內容:
-
進行
DNS
解析 -
建立
TCP
連接 -
客戶端發送
HTTP
請求 -
服務端響應
HTTP
資源 -
瀏覽器獲取響應內容,進行解析和渲染
以上任意一點都可進行無限擴展、延伸,但點到爲止纔是現在真正需要的。
性能指標
RAIL 模型
Google
爲前端頁面性能的評估提出了 RAIL
模型,核心內容如下:
-
Response
響應 -
Animation
動畫 -
Idle
空閒 -
Load
加載
常規性能指標
性能指標其實有不少的內容,但在這我們指列舉比較常用的幾種:
-
首次繪製(
First Paint,FP
) -
在渲染進程確認要渲染當前響應資源後,渲染進程會先創建一個空白頁面,通常把創建空白頁面的這個時間點稱爲
First Paint
,簡稱FP
-
所謂的 白屏時間 其實指的就是創建這個空白頁面到瀏覽器開始渲染非空白內容的時間,比如頁面背景發生變化等
-
首次內容繪製(
First Contentful Paint,FCP
) -
當用戶看見一些 "內容" 元素被繪製在頁面上的時間點,和白屏是不一樣,它可以是
文本
首次繪製,或SVG
首次出現,或Canvas
首次繪製等,即當頁面中繪製了第一個 像素 時,這個時間點稱爲First Content Paint
,簡稱FCP
-
首屏時間 / 最大內容繪製(
Largest Contentful Paint, LCP
) -
LCP
是一種新的性能度量標準,LCP
側重於用戶體驗的性能度量標準,與現有度量標準相比,更容易理解與推理,當首屏內容完全繪製完成時,這個時間點稱爲Largest Content Paint
,簡稱LCP
-
最大內容繪製應在
2.5s
內完成 -
首次輸入延遲(
First Input Delay, FID
) -
FID
測量的是當用戶第一次在頁面上交互的時候(點擊鏈接、點擊按鈕 或 自定義基於js
的事件),到瀏覽器實際開始處理這個事件的時間 -
首次輸入延遲應在
100ms
內完成 -
累積佈局偏移(
Cumulative Layout Shift, CLS
) -
CLS
是爲了測量 視覺穩定性,以便提供良好的用戶體驗 -
累積佈局偏移應保持在
0.1
或更少 -
首字節達到時間(
Time to First Byte,TTFB
) -
指的是瀏覽器開始收到服務器響應數據的時間(後臺處理時間 + 重定向時間),是反映服務端響應速度的重要指標
-
TTFB
時間如果超過500ms
,用戶在打開網頁的時就會感覺到明顯的等待
性能指標工具
通過上述內容瞭解了性能指標的相關內容和一些閥值,那麼接下來的問題是我們怎麼獲取一個網站的具體性能指標數據呢?
爲了方便還是得使用工具或者說是 API
,當然可以 自定義頁面性能指標 的計算方式,比如有些就是通過計算當前頁面 DOM
的 總節點數 和 嵌套層級 來計算一個網站的分數等,這裏就不再額外介紹。
Performance 面板(Google)
具體參數介紹可以看 Big shark@LX
[1] 大佬的文章,裏面介紹的非常詳細,這裏只列舉一些核心點。
火焰圖
Networks 指標
通過 Networks
指標可以查看到對應服務器加載資源的相關信息:
可以將鼠標 移動 或 點擊 到具體的請求上查看加載時間和加載速度,如下:
鼠標移入:
鼠標點擊:
Frames 指標
通過 Frames
指標可以查看頁面每一幀渲染時 CPU
所消耗的時間和持續時間 Duration
的信息,如下:
圖一:
圖二:
Timings 指標
通過 Timings
指標可以查看在上面列舉的一些性能指標的值,如下:
-
首次繪製(
First Paint,FP
) -
首次內容繪製(
First Contentful Paint,FCP
) -
首屏時間 / 最大內容繪製(
Largest Contentful Paint, LCP
) -
HTML
文檔被完全加載 和 解析完成的時間(DOMContentLoaded, DCL
)
Main 指標
Main
指標包含了加載過程的三個階段:
-
導航階段
-
主要是處理響應頭的數據,並執行一些老頁面退出之前的清理操作
-
解析
HTML
文件階段 -
主要是解析
HTML
數據、解析CSS
數據、執行JavaScript
來生成DOM
和CSSOM
-
生成位圖階段
-
主要是將生成的
DOM
和CSSOM
合併,包括了佈局 (Layout
)、分層、繪製、合成等一系列操作
Lighthouse 面板(Google)
Performance
面板最大的優點就是各種數據信息非常的全,但這也是它最大的缺點,數據信息龐大到需要自行過濾,對於不熟悉的開發者來說,還是需要一定的學習成本的。
相反,Lighthouse
面板中的信息就相對簡潔一些,除了檢測結果以外,還會提供對應的改進方案,真是考慮得妥妥的,主要檢測五個方面的內容:
-
Performance(性能)
-
Accessibility(可訪問性)
-
Best practice(最佳實踐)
-
SEO(搜索引擎優化)
-
Progressive Web App(漸進式 Web 應用)
可以通過 Analyze page load
按鈕來開始對頁面應用進行檢測,這裏以掘金首頁爲例:
下面以 Performance 性能 爲例簡單看一下具體包含的內容,由於篇幅有限,其他內容可自行測試並進行閱讀。
Performance 性能(舉一反三)
從性能指標的數據來看,只有 累積佈局偏移(Cumulative Layout Shift, CLS
) 滿足要求,其他指標顯示 黃色 和 紅色,意味着仍有改進的空間,特別是 首屏時間 是 2.9s
已經是超過了對應的閾值 2.5s
。
性能指標數據如下圖所示:
甚至還提供了對應的診斷結果,比如提到的圖片沒有設置對應的寬高:
Using the Node CLI
甚至還支持在 Node
環境運行,感興趣的自行去 npm
中查看 文檔[2] 即可,這裏不過多介紹。
性能指標數據收集
上述性能指標工具的能力已經足夠強大,覆蓋信息也很全面,但如果我們需要將頁面性能指標數據收集並上報又該怎麼辦呢?
首先排除的肯定是通過 性能指標工具 的方式來收集,一旦要檢測性能指標數據意味着得是不同的客戶端統計數據的結果合集(除非你願意一臺一臺客戶端來手動記錄和收集數據,呸,你願意你領導還不願意呢),最理想的方式當然是自動收集和上報,那就意味着這應該是代碼要乾的活!!!
既然有這樣的需求,那麼必定有對應的解決方案,您接着往下看!
Performance API
實際上在瀏覽器端的全局對象 window
上有一個名爲 performance
的屬性,它是一個用於支持 IE9
以上及 webkit
內核瀏覽器中用於記錄頁面 加載 和 解析 過程中關鍵時間點的機制,其兼容性在 caniuse
[3] 中的表現如下:
下面就簡單介紹一下和 window.performance
相關一些核心屬性和方法。
performance.timing 屬性
performance.timing
屬性中提供了很多關鍵的時間信息,我們可以通過這些時間節點來簡單的計算出需要的性能指標數據(不一定準確),計算方式如:
const {
domainLookupStart,
domainLookupEnd,
navigationStart,
loadEventEnd,
responseStart,
responseEnd,
connectStart,
connectEnd,
redirectStart,
redirectEnd,
domContentLoadedEventEnd,
domComplete,
} = performance.timing
// DNS 查詢時間
DNS = domainLookupEnd - domainLookupStart
// TCP 建立連接時間
TCP = connectEnd - connectStart
// 頁面重定向時間
Redirect = redirectEnd - redirectStart
// 首字節到底時間
TTFB = responseStart - navigationStart
// 首次渲染時間
FP = responseStart - navigationStart
// DOM 解析時間
DOM = domComplete - responseEnd
// 首屏時間
LCP = loadEventEnd - navigationStart
performance.getEntries() 方法
performance.getEntries()
方法可以獲取所有資源請求的時間數據,如下:
點擊可查看具體的資源信息,其他屬性和上述內容有重複,就不在額外介紹計算方式了,具體如下:
performance.now() 方法
performance.now()
方法可以精確計算程序執行時間,它會返回以微秒(百萬分之一秒)爲單位的時間,即更加精準,這也是它和 Date.now()
是不同點:
-
Date.now()
返回自 1970 年 1 月 1 日 00:00:00 (UTC) 到 當前時間 的 毫秒數 -
意味着
Date.now()
依賴於系統的當前時間,而系統時間可以被認爲修改,因此它的毫秒數並不準確 -
performance.now()
的時間是以恆定速率遞增的,不受系統時間的影響// Date.now() let a = 2, b = 3; const begin = Date.now(); console.log(' a + b = ', a + b); console.log('time = ', Date.now() - begin); // 2 // performance.now() let a = 2, b = 3; const begin = performance.now(); console.log(' a + b = ', a + b); console.log('time = ', performance.now() - begin); // 0.10000002384185791
Web Vitals
web-vitals
[4] 庫是 Google
推出的一個小型(約 1.5K
)模塊化庫,用於測量真實用戶的所有 Web Vitals
相關的指標,其重要核心指標信息如下(一圖勝千言):
接下來,讓我們通過 npx create-react-app my-react-app
來創建一個 react
項目,然後觀察一下它的項目結構:
是不是超級顯眼的 reportWebVitals.js
,在進入文件查看你會發現我們需要的核心性能指標都在裏面:
最後
前端性能優化這個內容是之前一直打算要寫的,終歸知識有所欠缺,到現在也算是邊學習邊輸出中,下一篇就針對性能優化的方案進行一些總結!!!
參考資料
[1]
Big shark@LX
: https://juejin.cn/post/7052918009555320839#heading-14
[2]
文檔:https://www.npmjs.com/package/lighthouse
[3]
caniuse
:https://caniuse.com/?search=performance
[4]
web-vitals
: https://www.npmjs.com/package/web-vitals
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/ezx1S3-ay22LwoL7pnJeyw