瞭解如何透過偵錯資訊歸因效能資料 以便找出並修正數據分析中實際的使用者問題
Google 提供兩種效能評估及偵錯工具:
- 研究室工具:如 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 資料) 的研究室,從研究室 (Lighthouse) 回報的 CLS 值會截然不同。如果您認為網頁可能含有大量互動內容,而在 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 的元素,可能會因使用者而異,但如果您匯總所有使用者的元素,就能產生影響最多使用者數量的變動元素清單。
找出並修正這些元素出現轉變的根本原因後,Analytics (分析) 程式碼就會隨著網頁的「最差」位移,開始記錄較小的變動。最後,回報的所有位移都會夠小,使網頁仍處於 0.1 的「良好」門檻!
與最大的 Shift 來源元素一起擷取的其他中繼資料可能有助於擷取:
- 最大轉變的時間
- 最大轉換時間的網址路徑 (適用於動態更新網址的網站,例如單一頁面應用程式)。
LCP
如要對欄位中的 LCP 進行偵錯,您需要的主要資訊是該特定網頁載入的最大元素 (LCP 候選元素)。
請注意,LCP 候選元素實際與使用者不同,即使顯示的內容完全相同,實際上也很常見。
問題的原因如下:
- 使用者裝置的螢幕解析度各有不同,導致網頁版面配置不同,因此可視區域內顯示不同的元素。
- 使用者不一定都會載入捲動至頂端的網頁。連結常會包含片段 ID 或甚至文字片段,因此網頁可能會在網頁的任何捲動位置載入並顯示。
- 內容可能會針對目前的使用者進行個人化,因此 LCP 候選元素可能因使用者而異。
這表示您無法假設哪個或一組元素會是特定網頁最常見的 LCP 候選元素。而且必須根據使用者的實際行為進行評估。
找出 LCP 候選元素
如要判斷 JavaScript 中的 LCP 候選元素,您可以使用 Largest Contentful Paint 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。這個 HTML 可在使用者輸入互動內容前,就先顯示在螢幕上,也就是在讓內容轉換為互動內容所需的 JavaScript 之前。
針對這些類型的應用程式,請務必瞭解第一個輸入是在飲水之前還是之後發生。如果結果顯示許多人在水份完成前嘗試與網頁互動,請考慮將網頁設為已停用或載入狀態,而非呈現互動狀態。
如果您的應用程式架構公開水份時間戳記,您可以將該時間戳記與 first-input
項目的時間戳記進行比較,以判斷第一個輸入內容是在飲水之前或之後發生。如果您的架構沒有公開該時間戳記,或者完全沒有使用飲水功能,另一個有用的信號可能是輸入時間是在 JavaScript 載入完成之前或之後。
網頁 HTML 完全載入並剖析後會觸發 DOMContentLoaded
事件,這包括等待任何同步、延遲或模組指令碼 (包括所有靜態匯入的模組) 載入完畢。因此,您可以使用該事件的時間,並與 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 版起,網頁體驗 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);
如需已揭露的偵錯信號完整清單,請參閱 Web Vitals 歸因說明文件。
製作資料報表並以視覺化方式呈現
開始收集偵錯資訊和指標值後,下一步是匯總所有使用者的資料,以便開始尋找模式和趨勢。
如上所述,您不一定要處理使用者遇到的每一個問題,尤其是首先是影響最多使用者的問題,而這也應該是對 Core Web Vitals 分數影響最大的問題。
如果是 GA4,請參閱如何使用 BigQuery 查詢資料及以視覺化方式呈現資料的專題文章。
摘要
希望這篇文章概述了使用現有效能 API 的具體使用方式,以及 web-vitals
程式庫以取得偵錯資訊,協助您根據實際使用者造訪的實際情形診斷效能。雖然本指南著重於網站體驗核心指標,但這些概念也適用於對 JavaScript 中可評估的任何成效指標進行偵錯。
如果您才剛開始評估效能,也已經是 Google Analytics (分析) 使用者,不妨先使用網站體驗指標報表工具,因為這項工具可支援 Core Web Vitals 指標的偵錯資訊報表。
如果您是分析供應商,且想要改善產品並為使用者提供更多偵錯資訊,不妨考慮採用本文所述的部分技術,但不要「只」只使用此處介紹的概念。這篇文章通常適用於所有分析工具;不過,個別分析工具可能 (也應) 擷取及回報更多偵錯資訊。
最後,如果您認為由於 API 中的功能或資訊遺失,而無法對這些指標進行偵錯,請將意見回饋傳送至 web-vitals-feedback@googlegroups.com。