效能優化的常見討論往往集中在「載入時間」上,例如程式碼分割、Lazy Loading 等手段。但是頁面載入完之後,使用者真正在操作網頁時的流暢度(Runtime Performance),才是體驗的關鍵。本章聚焦在 Chrome DevTools Performance Panel 的使用方式,看看怎麼用它揪出 runtime 階段的效能瓶頸。

開始 Profiling#

實務建議 進行 profiling 前,建議使用無痕視窗以避免擴充功能干擾測量結果。

DevTools 的 Performance Tab 左上角有兩顆按鈕:

  • Record:點擊後手動操作網頁,再停止錄製。適合測試特定行為。
  • Start profiling and reload page:自動 reload 並錄製,適合測試初始載入。

如果想模擬低階手機,可以在工具列的 CPU 選項調整速率(例如 6x slower),確保即使在效能較差的裝置上也能保持流暢。

解讀 FPS、CPU、NET 圖表#

FPS(Frame Per Second)#

動畫流暢度的最直觀指標,目標通常是 60 FPS。圖表中若出現紅色或粉紅色的條塊,代表掉幀,動畫可能不平順。FPS 過低不一定全是壞事,例如頁面靜止時本來就不需要持續產出新 frame。

CPU 與工作種類#

CPU 圖表會以不同顏色代表工作類別,與 Summary 對應:

顏色類別說明
灰色System瀏覽器內部任務
白色Idle閒置時間
黃色ScriptingJavaScript 執行與事件處理
綠色Painting繪圖、畫面繪製
紫色Rendering樣式計算、版面配置(Layout)
藍色Loading載入與解析 HTML

CPU 長期 maxed out 不一定是壞事(例如有持續動畫的網站),但若伴隨大量 Scripting 與掉幀,就值得審視是否能精簡程式碼,或把動畫改用 CSS 達成。

Memory:找出記憶體洩漏#

點開 Memory 選項可以看到藍色的 JS Heap 趨勢線。若曲線只升不降,很可能存在記憶體洩漏(Memory Leak)。也可以利用 GC 強制按鈕(垃圾桶圖示):

  • 在執行某段函式前後分別強制 GC。
  • 如果記憶體仍居高不下,洩漏的可能性就很大。

不過 GC 太頻繁也未必是好事——標記-清除(Mark-and-Sweep)會造成 Stop-the-world,太頻繁會直接影響流暢度。

Frames:每一幀的細節#

Frames 區塊呈現每一次 UI 更新的截圖。長時間沒更新的 frame 稱作 long frame。點擊單一 frame 可以在 Summary 看到 Duration、FPS、CPU Time 等資訊,便於精確定位卡頓的時刻。

Timing:載入相關指標#

Timing 顯示頁面在載入過程中觸發的關鍵時間點:

縮寫全名說明
DCLDOM Content LoadedHTML 被解析完成的時間
FPFirst Paint第一個像素被繪製的時間
FCPFirst Contentful Paint第一個有意義內容(文字或圖片)出現的時間
LCPLargest Contentful Paint可視區內最大元件載入完成的時間
Lonload所有資源載入完成的時間
TBTTotal Blocking TimeMain Thread 被阻塞的累計時間,越短越好

Experience:找出 Layout Shift#

Experience 區塊會標出觸發 Layout Shift 的時刻,正是 Core Web Vitals 中的 CLS 指標來源。

Network:資源依賴關係#

Network 顯示各資源的下載時序與依賴。雖然 Network Tab 通常更直覺,但在 Performance Tab 中可以與 CPU 任務疊在一起看,方便對照。

Main:CPU 火焰圖(Flame Graph)#

Main Section 是 Main Thread 的火焰圖(Flame Graph),呈現每一個 task 與其呼叫的子任務。圖中越下層的 task,越是在某個 parent task 內被觸發的。

Long Task 警告#

若 task 的右上角出現紅色三角形,代表這是一個 long task,可能是效能瓶頸。點選後可以看到呼叫堆疊與來源檔,甚至直接跳到 Sources Tab 對應的程式碼行數,對除錯非常方便。

除了 Main,可能還會出現 Frame(嵌入 iframe 的執行緒)與 Worker(例如 Web Workers)等項目,方便分析多執行緒場景。

範例:動畫前後的對比#

回到範例網站,原本的動畫直接改變元素的 top

element.style.top = `${currentTop + 1}px`;

這會觸發重新計算版面配置(Layout),Main Thread 一直忙在 Painting 與 Rendering 上,Idle 時間極少,掉幀嚴重。改用 transform 後:

element.style.transform = `translateY(${y}px)`;
<style>
  .item {
    will-change: transform;
  }
</style>

此時動畫只需在合成層上更新,不必觸發 Reflow / Repaint,profiling 出來的結果:

  • Frame Rate 大幅提升。
  • CPU 使用量降低。
  • Idle Time 變多,能即時回應使用者輸入,TTI(Time to Interactive (TTI))也跟著改善。

補充說明 Lighthouse 分數高並不等於使用體驗好。曾有 Lighthouse 滿分卻在實際操作時卡頓的案例,這時 Performance Tab 的 runtime profiling 才是抓問題的關鍵工具。

小結#

Chrome DevTools Performance Panel 提供的資訊量豐富,初次看到容易眼花。掌握 FPS、CPU、Memory、Frames、Timing、Experience、Main 等核心區塊,已經足以應付大多數 runtime 除錯需求。下次遇到卡頓或失幀時,不妨從這裡著手,配合火焰圖(Flame Graph)找出真正的瓶頸所在。

原文出處#