瞭解如何運用偵錯資訊為效能資料進行歸因, 藉此找出數據分析中的實際使用者問題並修正相關問題
Google 提供兩種效能評估及偵錯工具:
- 研究室工具:Lighthouse 這類工具。 Lighthouse 是指網頁在模擬環境中載入的模擬環境,而這些環境可以模擬各種條件 (例如網路速度緩慢或低階行動裝置)。
- 現場工具:Chrome 使用者體驗報告 (CrUX) 等工具,其來源為 Chrome 的匯總即時使用者資料。請注意,PageSpeed Insights 和 Search Console 等工具回報的欄位資料取自 CrUX 資料。
雖然現場工具提供的資料較準確,也就是實際可呈現實際使用者體驗的資料,但研究室工具通常較能協助您找出及修正問題。
CrUX 資料更能代表網頁的實際效能,但瞭解 CrUX 分數不太可能協助您找出改善效能的「方法」。
另一方面,Lighthouse 也會找出問題,並提供有關改善方向的具體建議。不過,Lighthouse 只會針對網頁載入時發現的效能問題提供建議。但不會偵測出僅因使用者互動 (例如捲動或點選網頁上的按鈕) 而引發的問題。
這將是一項重要問題:如何針對 Core Web Vitals 或其他實際使用者提供的效能指標擷取偵錯資訊?
本文將詳細說明可用哪些 API,針對目前各項網站體驗核心指標收集額外的偵錯資訊,以及如何在現有的分析工具中擷取這項資料。
用於歸因和偵錯的 API
CLS
在「網站體驗核心指標」指標中,CLS 選用在欄位收集偵錯資訊的方法最為重要。CLS 會在網頁整個生命週期中持續評估,因此使用者與網頁的互動方式 (捲動距離、點選的內容等) 就會對版面配置是否有位移,以及哪些元素移動等情況產生重大影響。
請參考以下來自 PageSpeed Insights 的報告:
相較於現場的 CLS (CrUX 資料),記錄的 CLS 值 (Lighthouse 資料) 值大不相同,如果您考慮到網頁可能含有大量互動內容,而在 Lighthouse 中進行測試時,就相當合理。
但即使您瞭解使用者互動會影響欄位資料,您還是需要知道網頁上的哪些元素在移動時,在第 75 個百分位數得到 0.3 分。
您可以利用 LayoutShiftAttribution 介面。
取得版面配置位移歸因
每個 Layout Instability API 發出的 layout-shift
項目都會顯示 LayoutShiftAttribution 介面。
如需這兩種介面的詳細說明,請參閱「針對版面配置位移進行偵錯」。基於本文的宗旨,您需要知道的重點是,開發人員可觀察網頁上的每個版面配置位移,以及哪些元素會移動。
以下範例程式碼會記錄每個版面配置位移和轉移的元素:
new PerformanceObserver((list) => {
for (const {value, startTime, sources} of list.getEntries()) {
// Log the shift amount and other entry info.
console.log('Layout shift:', {value, startTime});
if (sources) {
for (const {node, curRect, prevRect} of sources) {
// Log the elements that shifted.
console.log(' Shift source:', node, {curRect, prevRect});
}
}
}
}).observe({type: 'layout-shift', buffered: true});
在每次發生版面配置位移時,測量資料並傳送至數據分析工具可能並不實際。不過,只要監控所有位移,您就可以追蹤最嚴重的轉變,並且只回報有關這些變動的資訊。
我們的目標是找出並修正每位使用者的每個版面配置位移;我們的目標是找出影響最多使用者的轉場,因此在第 75 個百分位數中為網頁 CLS 貢獻最多。
此外,您不需要在每次有變化時計算最大的來源元素,只有在準備好將 CLS 值傳送至分析工具時才需要執行。
以下程式碼取得對 CLS 貢獻的 layout-shift
項目清單,並傳回最大偏移量的來源元素:
function getCLSDebugTarget(entries) {
const largestEntry = entries.reduce((a, b) => {
return a && a.value > b.value ? a : b;
});
if (largestEntry && largestEntry.sources && largestEntry.sources.length) {
const largestSource = largestEntry.sources.reduce((a, b) => {
return a.node && a.previousRect.width * a.previousRect.height >
b.previousRect.width * b.previousRect.height ? a : b;
});
if (largestSource) {
return largestSource.node;
}
}
}
找出造成最大變動最大的元素後,即可向數據分析工具回報。
在特定網頁上影響 CLS 程度最高的元素,可能因使用者而異,但如果將所有元素彙整在一起,就能產生一份清單,列出影響最多使用者的移動元素。
找出並修正這些元素轉移的根本原因後,分析程式碼就會開始回報較小的變動,因為網頁「最差」的變動。總的來說,所有回報的位移都會變得很小,因此網頁的情況都達到「良好」門檻 (0.1) 以下!
以下為與最大 Shift 來源元素一併擷取的其他中繼資料如下:
- 最大規模的轉變時
- 最大變動時的網址路徑 (適用於動態更新網址的網站,例如單一頁面應用程式)。
LCP
如要對欄位中 LCP 進行偵錯,您需要的主要資訊是該特定元素是該特定網頁載入最大的元素 (LCP 候選元素)。
請注意,LCP 候選元素與使用者彼此有所差異,這是很常見的情況。事實上,LCP 候選元素與使用者之間並不相同,即使是位於相同網頁的情況也不例外。
問題的原因如下:
- 使用者裝置的螢幕解析度不同,因此頁面版面配置會因此不同,因此可視區域會顯示不同的元素。
- 使用者不一定會載入捲動至最頂端的網頁。連結通常會包含片段 ID,甚至是文字片段,也就是說,頁面的任何捲動位置都能載入並顯示頁面。
- 內容可能會針對目前使用者進行個人化,因此 LCP 候選元素可能與使用者不同。
這表示您無法假設特定網頁的哪個或一組元素是最常見 LCP 候選元素。必須根據使用者的實際行為進行評估。
識別 LCP 候選元素
如要判斷 JavaScript 中的 LCP 候選元素,您可以使用最大內容繪製 API,也就是用來決定 LCP 時間值的 API。
觀察 largest-contentful-paint
項目時,您可以查看最後一個項目的 element
屬性來判斷目前的 LCP 候選元素:
new PerformanceObserver((list) => {
const entries = list.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP element:', lastEntry.element);
}).observe({type: 'largest-contentful-paint', buffered: true});
瞭解 LCP 候選元素後,您可以將該元素和指標值一併傳送至數據分析工具。與 CLS 相同,這可協助您找出最重要的元素,並優先進行最佳化。
除了 LCP 候選元素外,評估 LCP 子部分時間也有助於判斷與網站相關的具體最佳化步驟。
FID
如要對欄位中的 FID 進行偵錯,請記得,FID 只會測量整體第一個輸入事件延遲的「延遲部分」。這表示使用者與互動時在主要執行緒上發生的情況,其重要性不如互動時主執行緒上發生的情況。
舉例來說,許多支援伺服器端轉譯 (SSR) 的 JavaScript 應用程式都會提供靜態 HTML,並在與使用者輸入互動之前 (也就是讓內容互動式內容完成載入所需的 JavaScript 之前) 算繪到螢幕上。
針對這類型的應用程式,請務必瞭解是首次輸入內容是脫水的發生還是之後。如果結果顯示很多人嘗試在飲水完成前與頁面互動,請考慮將網頁轉譯為已停用或載入狀態,而非處於互動狀態。
如果您的應用程式架構公開了飲水時間戳記,您可以將該時間戳記與 first-input
項目的時間戳記進行比較,以判斷首次輸入是在飲水之前或之後發生。如果您的架構未顯示該時間戳記,或完全未使用水分,則另一個有用的信號可能是輸入發生在 JavaScript 載入之前或之後。
DOMContentLoaded
事件會在網頁的 HTML 完全載入並剖析後觸發,包括等待任何同步、延遲或模組指令碼 (包括所有靜態匯入的模組) 進行載入。因此,您可以使用該事件的時間,並與 FID 發生時間進行比較。
以下程式碼會觀察 first-input
項目,並記錄在 DOMContentLoaded
事件結束之前是否發生首次輸入內容:
new PerformanceObserver((list) => {
const fidEntry = list.getEntries()[0];
const navEntry = performance.getEntriesByType('navigation')[0];
const wasFIDBeforeDCL =
fidEntry.startTime < navEntry.domContentLoadedEventStart;
console.log('FID occurred before DOMContentLoaded:', wasFIDBeforeDCL);
}).observe({type: 'first-input', buffered: true});
辨別 FID 目標元素和事件類型
其他可能實用的偵錯信號是與元素互動的元素和互動類型 (例如 mousedown
、keydown
、pointerdown
)。雖然與元素本身的互動並不會產生 FID (提醒您,FID 只是事件延遲的總延遲部分),因此瞭解使用者與哪些元素互動,有助於判斷如何改善 FID。
舉例來說,如果使用者的最初互動大部分都與特定元素有關,請考慮在 HTML 中嵌入該元素所需的 JavaScript 程式碼,然後延遲載入其餘內容。
如要取得與第一個輸入事件相關聯的互動類型和元素,您可以參照 first-input
項目的 target
和 name
屬性:
new PerformanceObserver((list) => {
const fidEntry = list.getEntries()[0];
console.log('FID target element:', fidEntry.target);
console.log('FID interaction type:', fidEntry.name);
}).observe({type: 'first-input', buffered: true});
INP
INP 與 FID 非常類似,只是欄位中最實用的資訊位元如下:
- 互動的元素
- 原因類型
- 發生互動的時間
與 FID 一樣,導致緩慢互動的主因是封鎖的主執行緒,在 JavaScript 載入期間很常見。瞭解在網頁載入期間是否發生最緩慢的互動,將有助於判斷應採取哪些行動來修正問題。
與 FID 不同,INP 指標會考量互動的完整延遲時間,包括執行任何已註冊的事件監聽器花費的時間,以及在所有事件監聽器執行後繪製下一個影格所需的時間。這表示對於 INP 來說,瞭解哪些目標元素通常會導致互動速度緩慢,以及這些互動類型會更有幫助。
由於 INP 和 FID 都以 Event Timing API 為基礎,因此您在 JavaScript 中決定這項資訊的方式與前述範例非常類似。下列程式碼會記錄 INP 項目的目標元素和時間 (相對於 DOMContentLoaded
)。
function logINPDebugInfo(inpEntry) {
console.log('INP target element:', inpEntry.target);
console.log('INP interaction type:', inpEntry.name);
const navEntry = performance.getEntriesByType('navigation')[0];
const wasINPBeforeDCL =
inpEntry.startTime < navEntry.domContentLoadedEventStart;
console.log('INP occurred before DCL:', wasINPBeforeDCL);
}
請注意,這個程式碼並未示範如何判斷哪個 event
項目是 INP 項目,因為該邏輯會更複雜。不過,本節將說明如何使用 web-vitals JavaScript 程式庫取得這項資訊。
搭配 Web-Vitals JavaScript 程式庫使用
上節提供了一般建議和程式碼範例,協助您擷取偵錯資訊,以納入您傳送至數據分析工具的資料。
自第 3 版起,web-vitals JavaScript 程式庫包含的歸因版本,除了會顯示所有這些資訊,也顯示幾個其他信號。
以下程式碼範例說明如何設定包含偵錯字串的額外事件參數 (或自訂維度),有助於找出效能問題的根本原因。
import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';
function sendToGoogleAnalytics({name, value, id, attribution}) {
const eventParams = {
metric_value: value,
metric_id: id,
}
switch (name) {
case 'CLS':
eventParams.debug_target = attribution.largestShiftTarget;
break;
case 'LCP':
eventParams.debug_target = attribution.element;
break;
case 'FID':
case 'INP':
eventParams.debug_target = attribution.eventTarget;
break;
}
// Assumes the global `gtag()` function exists, see:
// https://developers.google.com/analytics/devguides/collection/ga4
gtag('event', name, eventParams);
}
onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);
這些程式碼是專為 Google Analytics (分析) 所設計,但我們建議改用其他分析工具。
此程式碼也僅顯示如何針對單一偵錯信號製作報表,但能夠按照指標收集多個不同信號並製作報表,可能很有用。舉例來說,如要對 INP 進行偵錯,建議您收集互動類型、時間以及互動的元素。web-vitals
歸因版本會顯示所有這些資訊,如以下範例所示:
import {onCLS, onFID, onINP, onLCP} from 'web-vitals/attribution';
function sendToGoogleAnalytics({name, value, id, attribution}) {
const eventParams = {
metric_value: value,
metric_id: id,
}
switch (name) {
case 'INP':
eventParams.debug_target = attribution.eventTarget;
eventParams.debug_type = attribution.eventType;
eventParams.debug_time = attribution.eventTime;
eventParams.debug_load_state = attribution.loadState;
break;
// Additional metric logic...
}
// Assumes the global `gtag()` function exists, see:
// https://developers.google.com/analytics/devguides/collection/ga4
gtag('event', name, eventParams);
}
onCLS(sendToGoogleAnalytics);
onLCP(sendToGoogleAnalytics);
onFID(sendToGoogleAnalytics);
onINP(sendToGoogleAnalytics);
如需公開的偵錯信號完整清單,請參閱網站 Firebase 歸因說明文件。
記錄資料並以視覺化方式呈現
開始收集偵錯資訊和指標值後,下一步是匯總所有使用者的資料,以開始尋找模式和趨勢。
如上所述,您不一定要解決使用者遇到的每一個問題,而且您需要先解決對最多使用者造成影響的問題,尤其是會影響最多使用者問題的問題,也應該是對 Core Web Vitals 分數帶來最大負面影響的問題。
對於 GA4,請參閱如何使用 BigQuery 查詢資料並以視覺化方式呈現資料的專屬文章。
摘要
希望本文有助於您瞭解使用現有效能 API 和 web-vitals
程式庫的特定方式,以取得偵錯資訊,以便根據實際使用者在現場造訪的情形診斷效能。雖然本指南著重於網站體驗核心指標,但對於透過 JavaScript 中可測量的任何成效指標偵錯也適用相關概念。
如果您才剛開始評估效能,而且您是 Google Analytics (分析) 使用者,建議您開始使用網站體驗指標報表工具,因為這項工具已支援核心網站體驗指標回報偵錯資訊。
如果您是分析廠商,想改善產品並為使用者提供更多偵錯資訊,請考慮採用本文所述的部分技巧,但不要「只」只將此處呈現的概念。本文主要是適用於所有分析工具,但可能 (也應該) 擷取並回報更多偵錯資訊。
最後,如果您覺得 API 中缺少功能或資訊導致偵錯指標受到限制,請將意見回饋傳送至 web-vitals-feedback@googlegroups.com。