評估與下一個顯示的內容的互動 (INP)

1. 簡介

本程式碼研究室會以互動方式,說明如何使用 web-vitals 程式庫測量 Interaction to Next Paint (INP)

必要條件

學習目標

  • 如何在網頁中新增 web-vitals 程式庫,並使用其歸因資料。
  • 使用歸因資料診斷要從何處著手,以及如何開始改善 INP。

軟硬體需求

  • 電腦必須能夠從 GitHub 複製程式碼,並執行 npm 指令。
  • 文字編輯器。
  • 使用新版 Chrome,才能正常進行所有互動評估。

2. 做好準備

取得並執行程式碼

程式碼位於web-vitals-codelabs存放區

  1. 在終端機中複製存放區:git clone https://github.com/GoogleChromeLabs/web-vitals-codelabs.git
  2. 前往複製的目錄:cd web-vitals-codelabs/measuring-inp
  3. 安裝依附元件:npm ci
  4. 啟動網路伺服器:npm run start
  5. 在瀏覽器中前往 http://localhost:8080/

試用頁面

本程式碼研究室會使用 Gastropodicon (熱門的蝸牛解剖學參考網站),探討 INP 的潛在問題。

Gastropodicon 試用網頁的螢幕截圖

嘗試與網頁互動,瞭解哪些互動速度緩慢。

3. 熟悉 Chrome 開發人員工具

開啟開發人員工具:依序選取「更多工具」 >「開發人員工具」選單在網頁上按一下滑鼠右鍵,然後選取「檢查」;或使用鍵盤快速鍵

在本程式碼研究室中,我們會使用「效能」面板和「控制台」。您隨時可以透過開發人員工具頂端的分頁標籤切換。

  • INP 問題最常發生在行動裝置上,因此請切換至行動裝置顯示模擬
  • 如果您在桌機或筆電上測試,效能可能會比在實際行動裝置上好得多。如要更貼近實際情況地查看效能,請按一下「效能」面板右上角的齒輪圖示,然後選取「CPU 減速 4 倍」

螢幕截圖:開發人員工具「效能」面板和應用程式並排顯示,且已選取 4 倍 CPU 減速

4. 安裝 web-vitals

web-vitals 是一個 JavaScript 程式庫,可評估使用者體驗的 Web Vitals 指標。您可以使用程式庫擷取這些值,然後將這些值信號傳送至數據分析端點,以供後續分析,目的是找出發生緩慢互動的時間和地點。

新增程式庫至網頁的方法有很多種。在自家網站上安裝程式庫的方式,取決於您管理依附元件的方式、建構程序和其他因素。如要瞭解所有選項,請務必查看程式庫的文件。

本程式碼研究室會從 npm 安裝並直接載入指令碼,避免深入探討特定建構程序。

您可以使用以下兩個版本的 web-vitals

  • 如要追蹤網頁載入時的 Core Web Vitals 指標值,請使用「標準」建構版本。
  • 「歸因」建構版本會在每個指標中加入額外的偵錯資訊,以診斷指標最終值的原因。

在本程式碼研究室中,我們需要歸因分析建構版本,才能評估 INP。

執行 npm install -D web-vitals,將 web-vitals 新增至專案的 devDependencies

web-vitals 新增至頁面:

index.html 底部新增歸因版本的指令碼,並將結果記錄到控制台:

<script type="module">
  import {onINP} from './node_modules/web-vitals/dist/web-vitals.attribution.js';

  onINP(console.log);
</script>

立即試用

開啟控制台後,請再次與網頁互動。您在頁面上點選任何項目時,系統都不會記錄任何內容!

INP 是在網頁的整個生命週期中測量,因此根據預設,web-vitals 會等到使用者離開或關閉網頁時,才回報 INP。這是信號傳送的理想行為,適用於分析等用途,但不太適合用於互動式偵錯。

web-vitals 提供 the reportAllChanges 選項,可產生更詳細的報表。啟用後,系統不會回報所有互動,但只要有互動比先前的互動慢,就會回報。

請嘗試將選項新增至指令碼,然後再次與網頁互動:

<script type="module">
  import {onINP} from './node_modules/web-vitals/dist/web-vitals.attribution.js';

  onINP(console.log, {reportAllChanges: true});
</script>

重新整理頁面後,系統應該就會將互動回報給控制台,並在出現新的最慢互動時更新。舉例來說,請試著在搜尋框中輸入內容,然後刪除輸入的內容。

開發人員工具控制台的螢幕截圖,其中成功列印了 INP 訊息

5. 歸因包含哪些內容?

首先,我們來看看大多數使用者與網頁的第一次互動,也就是 Cookie 同意聲明對話方塊。

許多網頁都有需要同步觸發 Cookie 的指令碼,因此使用者接受 Cookie 後,點擊就會變成緩慢的互動。這就是這裡的情況。

按一下「Yes」接受 (示範) Cookie,並查看現在記錄到開發人員工具控制台的 INP 資料。

記錄至開發人員工具控制台的 INP 資料物件

標準和歸因網頁指標建構版本都會提供這項頂層資訊:

{
  name: 'INP',
  value: 344,
  rating: 'needs-improvement',
  entries: [...],
  id: 'v4-1715732159298-8028729544485',
  navigationType: 'reload',
  attribution: {...},
}

從使用者點選到下一次繪製的時間長度為 344 毫秒,屬於「需要改善」的 INPentries 陣列包含與這項互動相關的所有 PerformanceEntry 值,在本例中只有一個點擊事件。

不過,如要瞭解這段時間的狀況,我們最感興趣的是attribution資源。為建構歸因資料,web-vitals 會找出與點擊事件重疊的長時間動畫影格 (LoAF)。LoAF 隨後會提供詳細資料,說明該影格期間的時間分配情形,包括執行的指令碼,以及在 requestAnimationFrame 回呼、樣式和版面配置中花費的時間。

展開 attribution 屬性即可查看更多資訊。資料更豐富。

attribution: {
  interactionTargetElement: Element,
  interactionTarget: '#confirm',
  interactionType: 'pointer',

  inputDelay: 27,
  processingDuration: 295.6,
  presentationDelay: 21.4,

  processedEventEntries: [...],
  longAnimationFrameEntries: [...],
}

首先是互動內容的相關資訊:

  • interactionTargetElement:與之互動的元素即時參照 (如果該元素尚未從 DOM 中移除)。
  • interactionTarget:用於在網頁中尋找元素的選取器。

接著,我們將時間劃分為幾個階段:

  • inputDelay:使用者開始互動 (例如點選滑鼠) 到該互動的事件監聽器開始執行的時間差。在本例中,即使 CPU 節流開啟,輸入延遲也只有約 27 毫秒。
  • processingDuration:事件監聽器執行完畢所需的時間。通常網頁會為單一事件設定多個監聽器 (例如 pointerdownpointerupclick)。如果這些監聽器都在同一個動畫影格中執行,就會合併到這個時間。在本例中,處理時間為 295.6 毫秒,占 INP 時間的大宗。
  • presentationDelay:從事件監聽器完成作業,到瀏覽器完成繪製下一個影格的時間。在本例中為 21.4 毫秒。

這些 INP 階段是診斷需要最佳化項目的重要信號。如要進一步瞭解這個主題,請參閱最佳化 INP 指南

再深入一點,processedEventEntries 包含 五個事件,而非頂層 INP entries 陣列中的單一事件。其中有何區別?

processedEventEntries: [
  {
    name: 'mouseover',
    entryType: 'event',
    startTime: 1801.6,
    duration: 344,
    processingStart: 1825.3,
    processingEnd: 1825.3,
    cancelable: true
  },
  {
    name: 'mousedown',
    entryType: 'event',
    startTime: 1801.6,
    duration: 344,
    processingStart: 1825.3,
    processingEnd: 1825.3,
    cancelable: true
  },
  {name: 'mousedown', ...},
  {name: 'mouseup', ...},
  {name: 'click', ...},
],

頂層項目是 INP 事件,在本例中為點擊。歸因 processedEventEntries 是在同一影格處理的所有事件。請注意,其中包含 mouseovermousedown 等其他事件,而不只是點擊事件。如果這些其他事件也很緩慢,瞭解這些事件就至關重要,因為這些事件都會導致回應速度緩慢。

最後是 longAnimationFrameEntries 陣列。這可能只是單一項目,但有時互動會跨越多個影格。這是最簡單的情況,只有一個長動畫影格。

longAnimationFrameEntries

展開 LoAF 項目:

longAnimationFrameEntries: [{
  name: 'long-animation-frame',
  startTime: 1823,
  duration: 319,

  renderStart: 2139.5,
  styleAndLayoutStart: 2139.7,
  firstUIEventTimestamp: 1801.6,
  blockingDuration: 268,

  scripts: [{...}]
}],

這裡有許多實用值,例如樣式設定所花費的時間量。「Long Animation Frames API」一文會更深入探討這些屬性。目前我們主要感興趣的是 scripts 屬性,其中包含的項目會提供導致影格長時間執行的指令碼詳細資料:

scripts: [{
  name: 'script',
  invoker: 'BUTTON#confirm.onclick',
  invokerType: 'event-listener',

  startTime: 1828.6,
  executionStart: 1828.6,
  duration: 294,

  sourceURL: 'http://localhost:8080/third-party/cmp.js',
  sourceFunctionName: '',
  sourceCharPosition: 1144
}]

在本例中,我們可以得知時間主要花在 BUTTON#confirm.onclick 上叫用的單一 event-listener。我們甚至可以看到指令碼來源網址,以及函式定義位置的字元位置!

外帶

從這項歸因資料,可以判斷這個案件的哪些資訊?

  • 互動是由點選 button#confirm 元素 (來自 attribution.interactionTarget 和指令碼歸因項目的 invoker 屬性) 觸發。
  • 主要時間用於執行事件監聽器 (相較於總指標 attribution.processingDuration)。value
  • 緩慢的事件監聽器程式碼會從 third-party/cmp.js (來自 scripts.sourceURL) 中定義的點擊事件監聽器開始。

這就足以瞭解需要進行最佳化的部分!

6. 多個事件監聽器

重新整理頁面,清除開發人員工具控制台,這樣 Cookie 同意聲明互動就不會再是最長的互動。

在搜尋框中輸入查詢。歸因資料會顯示什麼?你認為發生了什麼事?

歸因分析資料

首先,請先大致掃描測試試用版的一個範例:

{
  name: 'INP',
  value: 1072,
  rating: 'poor',
  attribution: {
    interactionTargetElement: Element,
    interactionTarget: '#search-terms',
    interactionType: 'keyboard',

    inputDelay: 3.3,
    processingDuration: 1060.6,
    presentationDelay: 8.1,

    processedEventEntries: [...],
    longAnimationFrameEntries: [...],
  }
}

這是與 input#search-terms 元素進行鍵盤互動時,INP 值不佳 (已啟用 CPU 節流) 的情況。大部分時間 (1061 毫秒,INP 總時間為 1072 毫秒) 都用於處理程序。

不過,scripts 的條目更有趣。

版面配置輾轉現象

scripts 陣列的第一個項目提供了一些實用情境:

scripts: [{
  name: 'script',
  invoker: 'BUTTON#confirm.onclick',
  invokerType: 'event-listener',

  startTime: 4875.6,
  executionStart: 4875.6,
  duration: 497,
  forcedStyleAndLayoutDuration: 388,

  sourceURL: 'http://localhost:8080/js/index.js',
  sourceFunctionName: 'handleSearch',
  sourceCharPosition: 940
},
...]

大部分的處理時間都發生在這個指令碼執行期間,也就是 input 監聽器 (呼叫者為 INPUT#search-terms.oninput)。函式名稱 (handleSearch) 和 index.js 來源檔案中的字元位置都會顯示。

不過,現在有新的屬性:forcedStyleAndLayoutDuration。這是指瀏覽器強制重新排版網頁時,在這個指令碼叫用中花費的時間。換句話說,執行這個事件監聽器所花費的時間有 78% (497 毫秒中的 388 毫秒) 實際上都浪費在版面配置抖動上。

應優先修正這個問題。

重複收聽者

就個別而言,接下來的兩個指令碼項目沒有特別之處:

scripts: [...,
{
  name: 'script',
  invoker