如何用瀏覽器開發者工具 (DevTools) 定位效能相關問題?

2025年7月3日

💎 加入 E+ 成長計畫 如果你喜歡我們的內容,歡迎加入 E+,獲得更多深入的軟體前後端內容

在前端工程師的工作中,經常會遇到各種問題,可能是某段程式碼運作不如預期,也可能是某個功能雖然正常,但是效能過慢。當遇到這些問題時,能否快速定位問題,並快速解決問題,會是區分一個前端工程師資深與否的分水嶺。

先前我們在 《什麼是可觀測性(Observability)? 為什麼需要可觀測性?》 一文談到,軟體工程師在解決問題的過程中,需要有工具協助直指問題核心,才不會在茫茫大海的可能性中,花費不必要的時間去猜問題是什麼。

這個概念在前端工程領域也是一樣的,當前端工程師要解某個 bug 時,也會需要搭配對應的工具來找問題;而對前端工程師來說,最需要熟知的工具,莫過於瀏覽器的開發者工具。因此,在接下來幾期的前端主題文中,我們會來談如何善用開發者工具,定位各類問題,這期會先從效能相關的問題開始談。

為什麼要懂瀏覽器的開發者工具?

如同在用任何工具之前,比起用工具本身,了解「為什麼」要用該工具是更重要的。在使用瀏覽器的開發者工具前,也需要先了解為什麼要懂瀏覽器的開發者工具,以下讓我們用幾個情境來說明。

假如某個前端工程師,要實作一個對接後端 API 的功能,讓使用者可以新增一筆資料,新增完後要馬上顯示新資料在畫面上;但是在實際對接後,發現功能並不如預期運作。

在這個狀況下,如果不用額外的工具,該前端工程師能做的,是在自己的程式碼中找問題在哪,然後去對照後端提供的 API 串接規格,來看是否有接對該 API。或者是實際的用 cURL 來呼叫 API 確保 API 是可以呼叫的,以及傳入的引數與收到的回覆都如預期。

但上面這個做法顯然會花很多時間,一個更快速找問題的方式,是打開瀏覽器的開發者工具,開啟 Network 面板,然後實際查看每一支 API 的呼叫,藉此快速定位是否是 API 對接的問題。假如發現 API 對接沒問題,就能快速回到程式碼查看其他部分,這時也可以透過埋 console 的方法,然後搭配開發者工具的 Console 面板,來查看不同的輸入與輸出結果。這種做法,會比上面的快速有效許多。

再來看看另一個例子,假如今天新功能在測試階段,產品端回報說頁面的加載異常的慢。如果在沒有額外工具的狀況下,只能盡可能地用上自己所知道的頁面效能優化的手段,但這種做法不是對症下藥,所以可能要試很多不同手段,才能有效優化。然而,如果有開發者工具,就可以開啟 Performance 面板,透過不同的方式,來快速定位加載慢是慢在哪。

希望透過上面兩個例子,讀者們有比較具體地感受到,當有了瀏覽器的開發者工具,前端工程師能更輕易地找出問題,這也是為什麼前端工程師需要懂如何善用開發者工具。

如何定位效能 (Performance) 相關問題?

首先,讓我們聚焦在 Performance 這個面板上,來談可以如何透過這個面板快速定位效能相關的問題。

查看瀏覽器生命週期事件

從使用者進到一個頁面之後,瀏覽器會也不同的生命週期事件,在 《請說明 DOMContentLoaded, load, beforeunload, unload 的觸發時機》 一文中,我們有介紹過這個面試中經常會考的問題。然而,比起去死記硬背這個面試題,用 Performance 面板中所展示的來理解會更有效。

Perfomance 面板
Perfomance 面板

假如打開 Perfomance 面板,然後點擊重新整理與錄製鍵,接著操作頁面,就可以出現類似上面這一張圖 (上面這張是拿 E+ 用的 Notion 頁面為例)。在圖中我們自己加了三個箭頭,分別是 DCL (DOMContentLoaded)、L (Load) 以及 LCP 的時間點。

可以看到,假如今天用 Performance 面板,就能很清楚地看到這些時間點,進而能夠去比較這些時間點是否有如預期發生。這能夠給前端工程師一個清楚的指引,來決定要不要花時間優化某些東西。

舉例來說,如果 DOMContentLoaded 太晚才發生,意味著瀏覽器花太多時間載入並解析 HTML 文件,如果要優化這塊,例如壓縮 HTML 檔案大小,移除不必要的註解和空白字符,或把阻塞 DOM 解析的 JavaScript 移到頁面底部,或用 defer 讓腳本在 DOM 解析完成後才執行 (在 《<script> 的 async 與 defer 有什麼不同?》 一文有詳談)。

查看每個函式所花費的時間

在看 Performance 面板時,我們也可以精細地去看每個函式所執行的時間。在這樣的一張火焰圖 (flame chart) 中,我們可以看到每一個函式呼叫所需的時間。

火焰圖 (flame chart)
火焰圖 (flame chart)

可以看到,在每一個函式被呼叫後,可能該函式底下又呼叫了其他函式,然後一層層呼叫下去。在這邊需要特別去區分兩個時間,一個是 total time 另一個是 self time (滑過會顯示),total time 是 self time 加上底下所有在被呼叫的函式所需的時間。

舉例來說,假如有個函式foo 呼叫 bar,這時 foo 的 total time 是 foo 的 self time 加上 bar 的 self time。

在有了這個理解後,在看火焰圖時,就要專注在看 self time,太長的 self time 就會需要特別注意。之所以不看 total time,是因為即使一個函式的 total time 很長,也不代表是這個函式有問題。以上方截圖來講,該函式的整個 total time 是 722.47 毫秒,雖然在圖上面這個函式的呼叫看似很長,但其實不用擔心,因為該函式的 self time 只有 2.46 毫秒。

查看主執行緒有沒有被任務佔滿

最後想談一個在看 Performance 面板時,高頻率會看的,是主執行緒是否過度繁忙。在 JavaScript 中,除非使用 worker 來幫忙,不然基本上是單一執行緒。換句話說,如果主執行緒忙著處理任務,沒辦法妥善處理好下一輪的繪製,就會有所謂「掉幀」的狀況,而對使用者來說,就會覺得瀏覽器很卡很頓。

下圖是來自 Chrome 官方的《Analyze runtime performance》一文的範例,如果在 Performance 面板中有看到這種紅色的小塊狀在 Main 上面,就代表主執行緒被榨乾。

紅色的小塊狀在 Main 上面
紅色的小塊狀在 Main 上面
圖片來源:Analyze runtime performance

《Measure performance with the RAIL mode》一文談到的,要讓人覺得畫面是順暢的,每秒需要渲染 60 幀 (也就是大家常看到的 60fps),換算起來每一幀最多只能有 16 毫秒 (1000 毫秒 / 每秒 60 幀),但因為瀏覽器會花約 6 毫秒處理繪製,所以真的能剩的是每幀 10 毫秒。

如果主行緒被榨乾,處理速度無法達到這個頻率,就會導致某些幀沒被繪製,就是上面提到的掉幀的卡頓狀況。要處理掉幀,透過 requestAnimationFrame 這類 Web API,能夠幫上大忙。

閱讀更多

在談完以上的基本內容後,接著我們會來談如何透過 Performance 面板查看 Web Vitals、requestAnimationFrame 實務上可以怎麼被用來解決效能問題,以及如何在 Network 面板上定位問題。這些內容都在 E+ 的主題文有近一步討論。

本文為 E+ 成長計畫的深度內容,截取段落開放免費閱讀。歡迎加入 E+ 成長計畫閱讀完整版本 (點此了解 E+ 的詳細介紹)。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們