2021 年 Web 核心性能指標(biāo)是什么?谷歌工程師告訴你,F(xiàn)MP 過(guò)時(shí)啦!
性能指標(biāo)對(duì)于網(wǎng)站來(lái)說(shuō)是一個(gè)長(zhǎng)期需要努力優(yōu)化提升的目標(biāo),谷歌為此推出了一系列工具,本文我想給大家介紹 web-vitals[1]這個(gè)由谷歌工程師編寫(xiě)的小而美的性能指標(biāo)測(cè)量 sdk。
本文是 ssh 整理來(lái)自 web-vitals 官網(wǎng)的一些內(nèi)容,感謝谷歌工程師們?cè)谛阅芊矫婢帉?xiě)的如此優(yōu)秀的資料。
如何定義性能模型
先講講性能,谷歌提出了著名的 RAIL 模型:
RAIL
分別對(duì)應(yīng)響應(yīng)、動(dòng)畫(huà)、空閑和加載,自上而下的在各個(gè)步驟延伸出各種優(yōu)化手段,具體的各階段介紹可以看 Measure performance with the RAIL model[2] 這篇文章,本文主要專(zhuān)注于講解如何去定義這些階段的性能好壞。
性能監(jiān)控的種類(lèi)
然后需要了解一下性能監(jiān)控的種類(lèi),性能監(jiān)控分為兩種:
- 合成監(jiān)控(Synthetic Monitoring,SYN)是一種模擬網(wǎng)頁(yè)加載或者腳本運(yùn)行來(lái)測(cè)量性能指標(biāo)的方式,輸出網(wǎng)頁(yè)性能報(bào)告。這種方式的價(jià)值在于提前發(fā)現(xiàn)可能存在的性能問(wèn)題,不依賴(lài)于用戶(hù)上報(bào)。Lighthouse[3] 就是谷歌開(kāi)發(fā)的非常著名的一種合成測(cè)試工具,它既可以作為瀏覽器插件運(yùn)行,也可以作為 cli 腳本,甚至以程序化的方式運(yùn)行在你的 Node.js 代碼中。
- 真實(shí)用戶(hù)監(jiān)控(Real User Monitoring,RUM)是記錄用戶(hù)真實(shí)操作的一種被動(dòng)監(jiān)控,它的特點(diǎn)是用戶(hù)真實(shí)的網(wǎng)頁(yè)交互中去評(píng)估和記錄性能數(shù)據(jù)。比如咱們常說(shuō)的性能監(jiān)控 sdk,就是為此而引入的。本文所介紹的 web-vitals 正是為了這種類(lèi)型的監(jiān)控而生。
合成監(jiān)控和真實(shí)用戶(hù)監(jiān)控相輔相成,前者用于在實(shí)驗(yàn)室環(huán)境下提前發(fā)現(xiàn)一些性能問(wèn)題;后者則深入到真實(shí)世界,和用戶(hù)設(shè)備、網(wǎng)速、環(huán)境等息息相關(guān)。
在此前提之下,谷歌也把性能指標(biāo)分為兩類(lèi):
- 實(shí)驗(yàn)室指標(biāo)(In the lab):使用工具在一致的環(huán)境中模擬頁(yè)面加載。
- 真實(shí)指標(biāo)(In the field):在真實(shí)用戶(hù)環(huán)境中加載并且和用戶(hù)交互。
核心性能指標(biāo)
Web Vitals 其實(shí)是谷歌發(fā)起的一項(xiàng)倡議,統(tǒng)一關(guān)鍵性能的標(biāo)準(zhǔn),幫助網(wǎng)站開(kāi)發(fā)者去統(tǒng)計(jì)最重要的指標(biāo),簡(jiǎn)化了許多復(fù)雜的概念。
基于長(zhǎng)期以來(lái)的性能指標(biāo)優(yōu)化體驗(yàn),最新的性能指標(biāo)主要專(zhuān)注于加載、交互、視覺(jué)穩(wěn)定,綜合下來(lái)就是下面的 3 個(gè)指標(biāo):
核心性能指標(biāo)
- Largest Contentful Paint (LCP)[4]: 最大內(nèi)容繪制,是用來(lái)測(cè)量加載的性能。最好保證在 2.5 秒以?xún)?nèi)出現(xiàn)。
- First Input Delay (FID)[5]: 第一次輸入延遲,用于測(cè)量可交互性。應(yīng)該在 100 毫秒以?xún)?nèi)。
- Cumulative Layout Shift (CLS)[6]:累計(jì)布局位移,用于測(cè)量視覺(jué)穩(wěn)定性。這個(gè)指標(biāo)應(yīng)該小于 0.1。
很多國(guó)內(nèi)的文章會(huì)提到 First Meaningful Paint (FMP),也就是首次有意義的渲染,但是這個(gè)指標(biāo)其實(shí)已經(jīng)在 Lighthouse 6.0 中被廢棄了,原因在于頁(yè)面的任何細(xì)微差異對(duì)這個(gè)指標(biāo)的影響都太大了,帶來(lái)了雙峰分布(bimodal distribution)的不一致性問(wèn)題。而且這個(gè)測(cè)量太依賴(lài)瀏覽器的實(shí)現(xiàn)細(xì)節(jié)了,意味著沒(méi)法在所有瀏覽器中標(biāo)準(zhǔn)化。
目前可以使用 Largest Contentful Paint (LCP)[7] 來(lái)替代它。
測(cè)量核心指標(biāo)
這些核心指標(biāo),目前都可以利用 web APIs 在 JavaScript 中進(jìn)行測(cè)量。
使用 web-vitals
為了封裝一些細(xì)節(jié)差異,谷歌提供了 GoogleChrome/web-vitals[8] 這個(gè)輕巧、準(zhǔn)備好用于生產(chǎn)的包,它只是 web APIs 的一層封裝,用戶(hù)不需要再關(guān)心指標(biāo)的收集時(shí)機(jī),環(huán)境判斷等問(wèn)題。
- import { getCLS, getFID, getLCP } from "web-vitals";
- function sendToAnalytics(metric) {
- const body = JSON.stringify(metric);
- // Use `navigator.sendBeacon()` if available, falling back to `fetch()`.
- (navigator.sendBeacon && navigator.sendBeacon("/analytics", body)) ||
- fetch("/analytics", { body, method: "POST", keepalive: true });
- }
- getCLS(sendToAnalytics);
- getFID(sendToAnalytics);
- getLCP(sendToAnalytics);
拿到了這些性能數(shù)據(jù)以后,你就可以自己清洗、整理并統(tǒng)計(jì)生成可視化的視圖,當(dāng)然你也可以用谷歌的 GoogleChromeLabs/web-vitals-report[9] 來(lái)生成可視化的數(shù)據(jù)看板。
手動(dòng)測(cè)量
當(dāng)然,你也可以利用底層 web APIs 來(lái)手動(dòng)測(cè)量,但是這就需要你自己決定上報(bào)的時(shí)機(jī)還有收集的次數(shù)等等。
LCP
- new PerformanceObserver((entryList) => {
- for (const entry of entryList.getEntries()) {
- console.log("LCP candidate:", entry.startTime, entry);
- }
- }).observe({ type: "largest-contentful-paint", buffered: true });
FID
- new PerformanceObserver((entryList) => {
- for (const entry of entryList.getEntries()) {
- const delay = entry.processingStart - entry.startTime;
- console.log("FID candidate:", delay, entry);
- }
- }).observe({ type: "first-input", buffered: true });
CLS
- let cls = 0;
- new PerformanceObserver((entryList) => {
- for (const entry of entryList.getEntries()) {
- if (!entry.hadRecentInput) {
- cls += entry.value;
- console.log("Current CLS value:", cls, entry);
- }
- }
- }).observe({ type: "layout-shift", buffered: true });
前兩者直接利用了 PerformanceObserver[10] 的指定 type 即可。CLS 相對(duì)特殊一些,因?yàn)槭琼?yè)面布局的累計(jì)位移,所以要一直監(jiān)聽(tīng)并且疊加這個(gè)值。
手動(dòng)測(cè)量的缺點(diǎn)在于,你需要自己遵循 Web Vitals 的測(cè)量標(biāo)準(zhǔn)去在相應(yīng)的時(shí)機(jī)開(kāi)始、結(jié)束測(cè)量,而且很多邊界情況也需要你自己處理。
如何優(yōu)化核心性能指標(biāo)
當(dāng)你測(cè)量了網(wǎng)站的核心性能指標(biāo)之后,下一步就是優(yōu)化它們。這幾篇文章可以給你很好的指導(dǎo):
- Optimize Largest Contentful Paint[11]
- Optimize First Input Delay[12]
- Optimize Cumulative Layout Shift[13]
其他性能指標(biāo)
雖然核心性能指標(biāo)是提供優(yōu)秀的用戶(hù)體驗(yàn)的關(guān)鍵,但也還有其他重要的指標(biāo)。
比如 Time to First Byte (TTFB) —— 首字節(jié)時(shí)間[14]和 First Contentful Paint (FCP) —— 首次內(nèi)容渲染[15] 對(duì)于加載體驗(yàn)來(lái)說(shuō)都很重要,對(duì)于診斷 LCP 來(lái)說(shuō)也很實(shí)用(比如服務(wù)器速度過(guò)慢,或者有阻塞渲染的資源)。
類(lèi)似的還有 Total Blocking Time (TBT) —— 總阻塞時(shí)間[16] 和 Time to Interactive (TTI) —— 首次可交互時(shí)間[17] ,它們都會(huì)影響 FID,是用來(lái)分析潛在的可交互性問(wèn)題的實(shí)驗(yàn)室指標(biāo)。它們并不屬于核心性能指標(biāo),因?yàn)樗鼈儾⒉贿m用于真實(shí)環(huán)境測(cè)量,也不會(huì)反應(yīng)用戶(hù)為中心的感受。
不斷發(fā)展的性能指標(biāo)
Web Vitals 和核心性能指標(biāo)代表了當(dāng)今用來(lái)衡量 Web 體驗(yàn)質(zhì)量的最佳可用信號(hào),未來(lái)會(huì)不斷的發(fā)展和改進(jìn)。
核心性能指標(biāo)和谷歌分析工具以及依賴(lài)它的頁(yè)面息息相關(guān),更改會(huì)產(chǎn)生廣泛的影響。因此,開(kāi)發(fā)者應(yīng)當(dāng)期望它是穩(wěn)定的,如果要更新的話(huà)應(yīng)該預(yù)先通知,并且應(yīng)該是以年為周期、可預(yù)期的更新。
其他性能指標(biāo)通常和特定的工具關(guān)聯(lián),相比起核心性能指標(biāo)更具有實(shí)驗(yàn)性質(zhì),更新的頻率可能會(huì)更高。
對(duì)于所有指標(biāo)的更新,這個(gè) CHANGELOG[18] 里都會(huì)清楚的記錄下來(lái)。
參考資料
Measure performance with the RAIL model[19]
Synthetic monitoring - Wikipedia[20]
Real user monitoring - Wikipedia[21]
Web Vitals[22]
User-centric performance metrics[23]
參考資料
[1]
web-vitals: https://github.com/GoogleChrome/web-vitals/
[2]
Measure performance with the RAIL model: https://web.dev/rail/
[3]
Lighthouse: https://github.com/GoogleChrome/lighthouse
[4]
Largest Contentful Paint (LCP): https://web.dev/lcp/
[5]
First Input Delay (FID): https://web.dev/fid/
[6]
Cumulative Layout Shift (CLS): https://web.dev/cls/
[7]
Largest Contentful Paint (LCP): https://web.dev/lcp/
[8]
GoogleChrome/web-vitals: https://github.com/GoogleChrome/web-vitals
[9]
GoogleChromeLabs/web-vitals-report: https://github.com/GoogleChromeLabs/web-vitals-report
[10]
PerformanceObserver: https://developer.mozilla.org/zh-CN/docs/Web/API/PerformanceObserver/PerformanceObserver
[11]
Optimize Largest Contentful Paint: https://web.dev/optimize-lcp/
[12]
Optimize First Input Delay: https://web.dev/optimize-fid/
[13]
Optimize Cumulative Layout Shift: https://web.dev/optimize-cls/
[14]
Time to First Byte (TTFB) —— 首字節(jié)時(shí)間: https://web.dev/time-to-first-byte/
[15]
First Contentful Paint (FCP) —— 首次內(nèi)容渲染: https://web.dev/fcp/
[16]
Total Blocking Time (TBT) —— 總阻塞時(shí)間: https://web.dev/tbt/
[17]
Time to Interactive (TTI) —— 首次可交互時(shí)間: https://web.dev/tti/
[18]
CHANGELOG: https://chromium.googlesource.com/chromium/src/+/master/docs/speed/metrics_changelog/README.md
[19]
Measure performance with the RAIL model: https://web.dev/rail/
[20]
Synthetic monitoring - Wikipedia: https://en.wikipedia.org/wiki/Synthetic_monitoring
[21]
Real user monitoring - Wikipedia: https://en.wikipedia.org/wiki/Real_user_monitoring
[22]
Web Vitals: https://web.dev/vitals/#core-web-vitals
[23]
User-centric performance metrics: https://web.dev/user-centric-performance-metrics