偵錯欄位效能

瞭解如何透過偵錯資訊歸因效能資料 以便找出並修正數據分析中實際的使用者問題

Google 提供兩種效能評估及偵錯工具:

  • 研究室工具:如 Lighthouse 工具,網頁會在模擬環境中載入,該環境可模擬各種狀況,例如網路速度緩慢和低階行動裝置。
  • 現場工具:Chrome 使用者體驗報告 (CrUX) 這類工具,以 Chrome 的匯總實際使用者資料為基礎。(請注意,PageSpeed InsightsSearch Console 等工具回報的欄位資料,是取自 CrUX 資料。)

雖然現場工具可提供更準確的資料,實際呈現實際使用者體驗的資料,但研究室工具通常更有助於找出及修正問題。

CrUX 資料最能代表網頁的實際效能,但瞭解 CrUX 分數不太可能幫助您瞭解「如何」改善效能。

另一方面,Lighthouse 會找出問題並提供改進的具體建議。不過,Lighthouse 只會針對網頁載入時發現的效能問題提供建議。但無法偵測僅限因使用者互動 (例如捲動或點選頁面上的按鈕) 而出現的問題。

這引發一個重要問題:如何擷取 Core Web Vitals 核心指標的偵錯資訊,或從實際使用者身上取得的其他成效指標?

本文將詳細說明哪些 API 可用來收集各項目前網站體驗核心指標指標的額外偵錯資訊,以及如何在現有的分析工具中擷取這些資料。

歸因和偵錯的 API

CLS

在所有網站體驗核心指標中,CLS 也許是收集欄位偵錯資訊最重要的指標。CLS 會在網頁的整個生命週期內進行測量,因此使用者與頁面互動的方式 (捲動距離、點擊的內容等等) 可能會對版面配置是否有位變化,以及哪些元素正在移動。

請參考 PageSpeed Insights 提供的下列報告:

採用不同 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 目標元素和事件類型

其他可能有用的偵錯信號是與元素互動的元素及其互動類型 (例如 mousedownkeydownpointerdown)。雖然與元素本身的互動並不會導致 FID (提醒您,FID 只是總事件延遲時間的延遲部分),因此瞭解哪些元素可能有助於判斷如何改善 FID。

舉例來說,如果使用者的最初互動大部分都與特定元素有關,請考慮在 HTML 中內嵌該元素所需的 JavaScript 程式碼,並延遲載入其餘部分。

如要取得與第一個輸入事件相關聯的互動類型和元素,您可以參照 first-input 項目的 targetname 屬性:

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 非常類似,它要在欄位中擷取最實用的資訊片段如下:

  1. 與哪個元素互動
  2. 互動類型為何
  3. 該互動發生的時間

與 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