Lighthouse Metrics:以使用者為出發點來探討效能的指標
07 Sep 2020本文說明 Lighthouse 以使用者為出發點來探討效能的指標。
網站的「效能」很重要 - 這簡直是網站開發與維運過程中最常聽到的老生常談之一,但當我們談到「效能好」或「速度快」時,我們到底指的是什麼?
效能可能和以下這些有關…
- 使用者 A 在瀏覽網站時使用很快的網路與性能很好的裝置,而使用者 B 可能是使用很慢的網路和性能很差的裝置。
- 網站 A 和網站 B 的載入時間相同,但網站 A 是漸進式的載入內容,而網站 B 是突然在某一刻完成載入。
- 網站很快的載入資源,但很久以後使用者才能與之互動、反應很慢。
以上都在談論效能所造成的影響,但考慮的是完全不同的東西…因此,當談到「效能」時,明確的指出所要評估的「指標」能讓我們更聚焦在要解決的問題上。
過去常用 load event 來衡量網站效能,雖然 load event 很明確的指出網頁生命週期的載入的這個時刻,但卻無法表達使用者在乎的細節。例如,當一個頁面載入時,伺服器很快的回應,讓這個頁面很快的將所有所需資源載入完成,而觸發 load event;而此頁面的主要內容可能是由另一支 API 取得的,可是伺服器回應得很慢 XD 此時使用者雖然可以看到頁面載入完成卻無法看到最重要的部份…這樣的狀況對使用者來說就是效能很差,不過就無法用 load event 來做測量。
例如…
利用 console 顯示 load 與 DOMContentLoaded 的時間點。
window.addEventListener('load', (event) => {
console.log('page is fully loaded', Date.now());
});
document.addEventListener('DOMContentLoaded', (event) => {
console.log('DOM fully loaded and parsed', Date.now());
});
頁面初始載入 timestamp 是 1617526685338 (放在 react lifecycle 的 constructor 裡面)
- DOM fully loaded and parsed 1617526686685
- page is fully loaded 1617526687342
1617526687342 - 1617526685338 = 2004 (ms)
因此..載入 HTML、js、樣式檔、圖檔,共花了 2004 ms
或是使用 Chrome DevTools 來看
- DOMContentLoaded Event: Timestamp 1346.5 ms
- Onload Event: Timestamp 2001.1 ms
因此..載入 HTML、js、樣式檔、圖檔,共花了 2001.1 ms
那麼,以使用者的觀點來看,所謂的效能是意味著哪些狀況呢?
- 這頁發生了嗎?導到這一頁順暢嗎?伺服器有回應嗎?
- 這頁是有用的嗎?對於使用者來說,有顯示足夠的內容來判斷是否有用了嗎?
- 這頁可以用嗎?使用者可與頁面元件互動嗎?還是在處理其他工作呢?
- 這頁載入的過程順暢嗎?有任何卡住或停頓嗎?
關於測量使用者對於效能感知的指標,有以下幾種
- 感知載入速度(perceived load speed):衡量頁面可載入和渲染使用者可見元件的速度。
- 載入互動性(load responsiveness):衡量頁面載入後多快可與使用者互動。
- 執行時互動性(runtime responsiveness):衡量頁面載入後多快可回應使用者互動。
- 視覺穩定性(visual stability):衡量頁面元件出現不預期的位移的頻率。
- 流暢性(smoothness):渲染漸變與動畫的維持穩定的幀率,以順暢地過渡到不同的狀態。
針對以上的指標,一方面是發現沒有任何單一指標可以含括效能相關的議題,另一方面也指出使用者針對效能所考量的各種面向。因此,Lighthouse 針對以使用者觀點的測量效能方式,提出了一些衡量的指標以供參考(目前不包含 runtime responsiveness)。
在看指標之前,先來看 RAIL。
RAIL
RAIL 是一個以使用者為中心、可用來衡量效能的模型。這個模型將使用者的行為分為幾種類型,並針對這些類型定義改進效能的目標。也就是說,RAIL 分別代表 app 生命週期的不同階段 - Response、Animation、Idle 和 Load,使用者對於這些階段皆有不同的期待,因此對於改善效能的目標就是依據使用者對於這些階段所能接受的延遲時間來定義的。
RAIL 的定義如下
- R:Response,收到使用者與 UI 互動後得到反應的時間,最多是 100ms。
- A:Animation,盡量符合 60fps,最多 16ms。實際上,由於瀏覽器有很多工作要做,因此大約是 10 ~ 12ms。
- I:Idle,互動結束後等待下一次與使用者互動的空擋,大約是 50ms。
- L:Load,頁面資源載入最多花 1 秒。
舉例來說,使用者點擊按鈕後會是這樣的狀況…
說明
- 使用者點擊按鈕後,期望得到回饋,這個回饋可能是開始某個動畫。從點擊到動畫開始,最多讓使用者等待 100 ms。
- 動畫從開始到結束,維持很順暢的更新頻率 60 fps。
- 動畫結束後,可能是 (1) 進入 idle 狀態待使用者下一次的互動(最多等待 50ms)或 (2) 給予另外的回饋(最多等待 100ms)。
測量 Metrics 的方式
- Lab:工具模擬網頁載入並之互動,可重現可控制的環境,用於開發時期。
- Field:現實生活中的有實際使用者的狀況下,網頁載入並之互動。無法重現、不可控制的環境,例如:顯示個人化廣告。用於在正視環境上蒐集實際狀況的資料。
Metrics 可測試的環境
# | Lab | Field |
---|---|---|
First contentful paint (FCP) | v | v |
Largest contentful paint (LCP) | v | v |
First input delay (FID) | x | v |
Time to Interactive (TTI) | v | x |
Total blocking time (TBT) | v | x |
Cumulative layout shift (CLS) | v | v |
Metrics
Lighthouse 針對以使用者觀點的測量效能的指標,有以下幾種:
- First Contentful Paint (FCP):測量感知載入速度,實際上是測量頁面載入時使用者可在螢幕上看到的任何元素的所需時間。
- Largest Contentful Paint (LCP):測量感知載入速度,實際上是測量頁面最大面積內容已載入的所需時間。
- First Input Delay (FID):測量載入互動性,實際上是測量使用者第一次與頁面互動到瀏覽器有空回應的時間,也就是測量接收到 input event 與 main thread 狀態為 idle 的這段間隔時間的值。
- Time to Interactive (TTI):測量載入互動性,實際上是測量頁面載入後,使用者可與瀏覽器互動並能給予回應的時間,也就是測量在長時間工作結束後、main thread 可 idle 五秒 (quiet window) 前的這段時間。
- Total Blocking Time (TBT):測量載入互動性,實際上是測量 main thread 被 long task (> 50ms) block 的時間。
- Cumulative Layout Shift (CLS):頁面視覺的穩定度,實際上是測量頁面存活週期間,每個可見元素移動位置的分數的總和。
- Speed Index:頁面在視覺上的流暢性,實際上是測量頁面在載入過程中,視覺上變化的速度。
以下分別說明,並且為了確保此 App 的大多數的使用者能達到這個目標,評估桌上機和行動裝置的第 75 個百分位(註 1)必須要能達到此這個標準。
我們在閱讀 Lighthouse 的報告的時候,可能會困惑這些指標與最後所得到的分數是什麼關係…
下圖是 Lighthouse 的效能測量結果。
指標和分數有什麼關係呢?佔比是這樣的…
- First Contentful Paint — 15%
- Speed Index ————– 15%
- Largest Contentful Paint - 25%
- Time to Interactive —— 15%
- Total Blocking Time —— 25%
- Cumulative Layout Shift – 5%
這是衡量了使用者的角度後所得到的佔比,後續的實驗可能會再更新指標或比例。若想知道更多指標與分數的資訊,可參考這裡。
First Contentful Paint (FCP)
First Contentful Paint (FCP) 是測量感知載入速度的一個指標,FCP 是指頁面載入了使用者可在螢幕上看到的任何元素的時間點,快速的 FCP 確保使用者不是空等。「任何元素」可以是任何的文字、圖檔或非白色的背景色。
什麼是好的 FCP?
- Good: < 1.8 秒
- Needs improvement: 1.8 ~ 3 秒
- Poor: > 3 秒
Largest Contentful Paint (LCP)
Largest Contentful Paint 是測量測量感知載入速度的一種指標,實際上是測量頁面主要內容(或稱最大面積)內容已載入的所需時間,這個計算時間會在使用者開始與頁面互動時結束。快速的 LCP 能讓使用者確保該頁對他們是有用的。
範例如下圖這個頁面載入的流程,一開始畫面是什麼都沒有的,然後出現了 loading icon 暗示使用者網站仍在持續載入資源,接著出現了第一個元件,最後顯示完整的網頁內容。
因此…
- 使用者可以在螢幕上看到任何東西的時間點,即是有 loading icon 的時間點,從開始載入到 loading icon 出現的這段時間即是 FCP,約是 400ms。
- 從開始載入到顯示主要內容(此圖為文字區塊)的時間點即是 LCP,約是 900ms。FCP 只測量畫面初始載入的狀況,但若畫面是顯示初始畫面或 loadig icon,那麼 LCP 就變得很有用。
對照實際狀況來看…以這個網頁為例,從 Chrome DevTools 的 Performance 標籤頁的 timeline 可以看到標記,點選「LCP」可以圈出到底是指哪一塊 DOM 元素和顯示相關資訊,例如:節點類型、timestamp 等。
如圖,認定主要內容是由 <p>
所包含的文字片段 To provide a good user experience...
,LCP 時間是 763 ms,
這裡可以注意幾點…
- 所謂的「主要內容」是指最大尺寸的以下任一者:圖檔(
<img>
元素)、影音檔(<video>
元素)、<svg>
內嵌的<img>
元素、使用url(...)
來載入的 css 背景圖片、區塊元素內的文字或行內文字內的元素。 - 所謂的「最大尺寸」基本上是指使用者看到的大小,但若像圖檔可能會因響應式網頁等狀況放大縮小,則選擇較小的回報。例如:此圖原始尺寸較大,但為了適應在較小的區塊而調整顯示為較小尺寸,則回報這個小的尺寸;反之,若此圖原始尺寸較大,但為了適應在較大的區塊而調整為較大的尺寸,則回報原始較小的尺寸。並且,由 CSS 所設定的 margin、padding、border 都不算在這回報的尺寸範圍內。
- 「主要內容」可能會隨著新的元素加入或變更來源而改變,瀏覽器會因此隨之調整,可參考這裡。
什麼是好的 LCP?
- Good: < 2.5 秒
- Needs improvement: 2.5 ~ 4 秒
- Poor: > 4 秒
First Input Delay (FID)
First Input Delay (FID) 是測量載入互動性,實際上是測量使用者第一次與頁面互動(例如:點某個連結、點某個按鈕等)到瀏覽器有空回應的時間,也就是測量接收到 input event 與 main thread 狀態為 idle 的這段間隔時間的值(又可稱為 input delay 或 input latency)。較低的 FID 可讓使用者更快確認此頁面是否可用。
注意…
- 發生 input delay 的原因是瀏覽器的 main thread 持續忙碌中,導致無法立刻處理使用者的互動而給予反應,例如:瀏覽器仍忙於剖析和執行剛下載好的 JavaScrpt 檔案,而無法執行任何事件監聽器。
- 由於 FID 專注的是 RAIL 的「R,反應」,因此目前決定只偵測 input(包含
<input>
、<textarea>
、<select>
、<a>
)的 click、tap、key press 事件;其他如 scroll 或 zoom 被歸類在「A,動畫」就不在討論範圍內。
如上圖所示,當頁面發出要求資源的網路請求時(灰色區塊),在檔案下載完畢後,瀏覽器的 main thread 都需要花不等的一段時間來做處理(藍色區塊,每個區塊視為一個 task)。
當 main thread 在花時間處理處理這些 task 時,真的是非常忙碌的,若此時使用者嘗試和頁面元件互動,像是點某個按鈕,則必須等到這個 task 結束後才能做出反應、開始處理,這一段等待的時間即是前面所說的 FID。
什麼是好的 FID?
- Good: < 100 ms
- Needs improvement: 100 ~ 300 ms
- Poor: > 300ms
Time to Interactive (TTI)
Time to Interactive (TTI) 是測量載入互動性,實際上是測量頁面載入後,使用者可與瀏覽器互動並能給予回應的時間,也就是測量在長時間工作結束後、main thread 可 idle 五秒 (quiet window) 前的這段時間。見上圖。所謂 quiet window 是指沒有長時間 (> 50 ms) 的 task,且沒有超過 2 個 GET 網路請求。這也是想測試 RAIL 的「R,反應」,意即此頁面是否能與使用者互動。
什麼是好的 TTI?
TTI 必須低於 5 秒才是好的。
Total Blocking Time (TBT)
Total Blocking Time (TBT) 是測量載入互動性,實際上是測量在 FCP 和 TTI 之間,main thread 被 long task (> 50ms) block 的時間,也就是只算「超過 50ms」的部份。
如下圖所示,這裡有 5 個 task,其中有 3 個 task 的執行時間超過 50ms。
計算超過 50ms 的部份,也就是被 block 的時間,因此 TTI 為 200 + 40 + 105 = 345 ms。
什麼是好的 TBT?
- Good: < 300 ms
- Needs improvement: 300 ~ 600 ms
- Poor: > 600ms
Cumulative Layout Shift (CLS)
Cumulative Layout Shift (CLS) 是用於測量頁面視覺的穩定度,實際上是測量頁面存活週期間,每個可見元素移動位置的分數的總和。它有助於量化使用者經歷意外的版位移動的頻率,較低的 CLS 有助於確保頁面是令人愉悅。
若頁面有太多元素處於不穩定的狀態,意即不斷的位移,可能導致使用者難以對正確的元件互動(例如:按錯按鈕、無法正確理解目前頁面呈現的資訊等)。
頁面有不預期的移動的元素往往是因為
- 非同步載入資源
- 動態加入 DOM 物件,例如:無法預知尺寸大小的圖檔或影片、字體變大變小、第三方套件或廣告動態縮放大小
以上問題可能與使用的測試圖片可能已在開發者環境的被快取起來、API 回應速度不同有關,而導致這個問題在在開發環境與真正客戶所使用的正式產品環境往往差異很大,因此需要使用 CLS 來協助評斷這種畫面元素不預期移動的頻率,以期改善這個問題。
要怎麼計算 Cumulative Layout Shift 呢?公式是這樣的…CLS = impact fraction * distance fraction
,範例如下。
如上圖所示,使用者一開始在畫面上看到的狀態(如圖左),接著載入廣告(如圖右),並將原本顯示圖文的區塊往下擠,因此…
- impact area 是紅色虛線區塊,約佔整個可見畫面的 2/3,因此
impact fraction = impact area / whole area = 2/3
。 - 找出移動最多距離的元素,也就是圖文區塊,其中圖文的區塊往下移,見藍色虛線區塊移動範圍,約移動整個可見畫面的 1/3,因此
distance fraction = the greatest distance has moved = 1/3
。
也就是說,得到 CLS = impact fraction * distance fraction = 2/3 * 1/3 = 2/9 ~ 0.22
。
關於 CLS 常見的解法是使用 CSS transform 而非改變 width、height、position 的值。
什麼是好的 CLS?
- Good: < 0.1
- Needs improvement: 0.1 ~ 0.25
- Poor: > 0.25
Speed Index
Speed Index 是測量頁面在視覺上的流暢性,實際上是測量頁面在載入過程中,視覺上變化的速度,愈低的 Speed Index 表示過程愈流暢。
計算方式如下…
這個公式算的是反向的面積…其中 x 軸是經過的毫秒數,y 軸是完成百分比
如下圖所示,若有一頁面 Page 1 的載入過程是從一開始的緩慢(約 10%)突然進展到 50% 再快速到達 100%;相較於 Page 2 是漸進的持續載入,其中每一格代表 1 秒,約 10 秒完成載入。
經計算後…
- Page 1 的 Speed Index 是 6500
- Page 2 的 Speed Index 是 5000
Page 1 的 6500 > Page 2 的 5000,因此 Page 2 的載入過程較佳、較為流暢。
什麼是好的 Speed Index?
Speed Index 應小於 1000。
新制的算法是換算為秒數,也就是
- Good: < 4.4 秒
- Needs improvement: 4.4 ~ 5.8 秒
- Poor: > 5.8 秒
總結
目前 Lighthouse 預設環境是 Moto G4。
# | Metrics | 縮寫 | 定義 | Good | Needs improvement | Poor |
---|---|---|---|---|---|---|
1 | First Contentful Paint | FCP | 測量感知載入速度,實際上是測量頁面載入使用者可在螢幕上看到的任何元素的所需時間。 | < 1.8 秒 | 1.8 ~ 3 秒 | > 3 秒 |
2 | Largest Contentful Paint | LCP | 測量感知載入速度,實際上是測量頁面最大面積內容已載入的所需時間。 | < 2.5 秒 | 2.5 ~ 4 秒 | > 4 秒 |
3 | First Input Delay | FID | 測量載入互動性,實際上是測量使用者第一次與頁面互動到瀏覽器有空回應的時間,也就是測量接收到 input event 與 main thread 狀態為 idle 的這段間隔時間的值。 | < 100 ms | 100 ~ 300 ms | > 300ms |
4 | Time to Interactive | TTI | 測量載入互動性,實際上是測量頁面載入後,使用者可與瀏覽器互動並能給予回應的時間,也就是測量在長時間工作結束後、main thread 可 idle 五秒 (quiet window) 前的這段時間。 | TTI < 5 秒 | ||
5 | Total Blocking Time | TBT | 測量載入互動性,實際上是測量 main thread 被 long task (> 50ms) block 的時間。 | < 300 ms | 300 ~ 600 ms | > 600ms |
6 | Cumulative Layout Shift | CLS | 頁面視覺的穩定度,實際上是測量頁面存活週期間,每個可見元素移動位置的分數的總和。 | < 0.1 | 0.1 ~ 0.25 | > 0.25 |
7 | Speed Index | 頁面在視覺上的流暢性,實際上是測量頁面在載入過程中,視覺上變化的速度。 | Speed Index 應小於 1000;新制:< 4.4 秒 | 新制:4.4 ~ 5.8 秒 | 新制:> 5.8 秒 |
備註
- [註 1] 百分位數:如果將一組數據從小到大排序,並計算相應的累計百分位,則某一百分位所對應數據的值就稱為這一百分位的百分位數,以 Pk 表示第 k 百分位數。
- [註 2] Real User Monitoring (RUM) vs Synthetic Monitoring (STM),如下表格所示
# | Real User Monitoring | Synthetic Monitoring |
---|---|---|
分類 | passive monitoring | active monitoring |
監測方式 | 監測真正的使用者在操作網站功能的效能並搜集與分析資料 | 模擬使用者的行為來測試網站的效能 |
目的 | 了解長期走向 | 診斷與解決短期問題 |
範例或產品 | Stackify | Lighthouse |
優點 | 全方位監測;能找出真實的困境 | 測試單純,能定期追蹤比較;可指定特定時間環境;可用於非正式環境 |
缺點 | 需要流量;缺乏測試基準;只能用於正式環境 | 並非真實狀況;可預測的固定測試情境而難以發覺未知問題 |
對象 | 管理者 | 技術人員 |
擬真度 | 真 | 假 |
參考資料
- web.dev - Metrics
- Lighthouse / Performance / Metrics
- Understand and improve the Time To Interactive
- Web Performance Fundamentals: what is the Speed Index?
- Speed Index Explained - Another Way to Measure Web Performance
- Speed Index is now expressed in seconds?
- Microsoft Math Solver:這工具可協助算微積分 XD
- User-centric performance metrics
- Lighthouse performance scoring
- Real User Monitoring (RUM) vs. Synthetic Monitoring Comparison:見註 2
(2020/09/11 更新) 公司內部小分享,補上投影片。