自訂指標

以使用者為中心的指標可在任何網站上普遍評估,因此非常有用。這些指標可讓您:

  • 瞭解實際使用者對整個網際網路的體驗。
  • 比較您和競爭對手的網站。
  • 在數據分析工具中追蹤實用且可採取行動的資料,無須編寫自訂程式碼。

通用指標可提供良好的基準,但在許多情況下,您需要評估更多指標,才能完整掌握特定網站的使用體驗。

您可以使用自訂指標評估網站體驗的某些面向,這些面向可能只適用於您的網站,例如:

  • 單頁應用程式 (SPA) 從一個「頁面」轉換到另一個「頁面」所需的時間。
  • 網頁顯示從資料庫擷取的資料,所需的時間長度 (以秒為單位)。
  • 伺服器端算繪 (SSR) 應用程式重新整理所需的時間。
  • 回訪者載入資源的快取命中率。
  • 遊戲中點擊或鍵盤事件的事件延遲時間。

用於評估自訂指標的 API

以往,網頁開發人員沒有太多低階 API 可用來評估成效,因此必須使用駭客手法,才能評估網站的成效。

舉例來說,您可以執行 requestAnimationFrame 迴圈並計算每個影格之間的差異,判斷主執行緒是否因長時間執行的 JavaScript 工作而遭到阻斷。如果差異值明顯長於螢幕的幀率,您可以將其回報為長時間工作。不過,我們不建議使用這類駭客手法,因為這類手法本身會影響效能 (例如耗盡電池電量)。

有效評估效能的第一個原則,就是確保效能評估技術本身不會造成效能問題。因此,對於您在網站上評估的任何自訂指標,建議盡量使用下列任一 API。

Performance Observer API

瀏覽器支援

  • Chrome:52。
  • Edge:79。
  • Firefox:57。
  • Safari:11。

資料來源

Performance Observer API 是一種機制,可收集並顯示本頁所述其他所有效能 API 的資料。瞭解這項概念,才能取得優質資料。

您可以使用 PerformanceObserver 被動訂閱與成效相關的事件。這可讓 API 回呼在閒置期間觸發,也就是說,回呼通常不會影響網頁效能。

如要建立 PerformanceObserver,請傳遞回呼,以便在每次調度新的成效項目時執行。接著,您可以使用 observe() 方法,告訴觀察器要監聽哪些類型的項目:

const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

po.observe({type: 'some-entry-type'});

下列各節將列出可供觀察的所有項目類型,但在較新的瀏覽器中,您可以透過靜態 PerformanceObserver.supportedEntryTypes 屬性檢查可用的項目類型。

觀察已發生的項目

根據預設,PerformanceObserver 物件只能在項目發生時進行觀察。如果您想延後載入效能分析程式碼,以免阻斷優先順序較高的資源,這可能會導致問題。

如要取得歷史記錄項目 (發生後),請在呼叫 observe() 時將 buffered 標記設為 true。瀏覽器會在首次呼叫 PerformanceObserver 回呼時,從效能輸入緩衝區中加入歷來記錄,最多可達該類型的最大緩衝區大小

po.observe({
  type: 'some-entry-type',
  buffered: true,
});

應避免使用的舊版效能 API

在 Performance Observer API 推出之前,開發人員可以使用下列三種方法存取效能項目,這些方法是在 performance 物件上定義:

雖然這些 API 仍受支援,但我們不建議使用這些 API,因為您無法透過這些 API 監聽新項目何時產生。此外,許多新的 API (例如 largest-contentful-paint) 並未透過 performance 物件公開,而是只透過 PerformanceObserver 公開。

除非您特別需要與 Internet Explorer 相容,否則最好避免在程式碼中使用這些方法,並改用 PerformanceObserver

User Timing API

瀏覽器支援

  • Chrome:28。
  • Edge:12。
  • Firefox:38。
  • Safari:11。

資料來源

User Timing API 是用於時間指標的通用評估 API。可讓您任意標記時間點,然後在稍後測量這些標記之間的時間長度。

// Record the time immediately before running a task.
performance.mark('myTask:start');
await doMyTask();

// Record the time immediately after running a task.
performance.mark('myTask:end');

// Measure the delta between the start and end of the task
performance.measure('myTask', 'myTask:start', 'myTask:end');

雖然 Date.now()performance.now() 等 API 也提供類似功能,但使用 User Timing API 的好處在於,它能與效能工具完美整合。舉例來說,Chrome 開發人員工具會在「效能」面板中以視覺化方式呈現使用者時間測量結果,許多數據分析供應商也會自動追蹤您所做的任何測量,並將時間長度資料傳送至其數據分析後端。

如要回報使用者時間測量結果,您可以使用 PerformanceObserver,並註冊觀察 measure 類型項目:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

// Start listening for `measure` entries to be dispatched.
po.observe({type: 'measure', buffered: true});

Long Tasks API

瀏覽器支援

  • Chrome:58。
  • Edge:79。
  • Firefox:不支援。
  • Safari:不支援。

資料來源

Long Tasks API 可用於瞭解瀏覽器主執行緒遭到阻斷的時間長度,以便判斷是否會影響影格速率或輸入延遲。API 會回報執行時間超過 50 毫秒的任何工作。

每當您需要執行耗用資源的程式碼,或載入及執行大型指令碼時,追蹤該程式碼是否會阻斷主執行緒就很有幫助。事實上,許多較高層級的指標都是以 Long Tasks API 本身為基礎 (例如互動準備時間 (TTI)總封鎖時間 (TBT))。

如要判斷長時間工作任務何時發生,您可以使用 PerformanceObserver,並註冊觀察 longtask 類型項目:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

// Start listening for `longtask` entries to be dispatched.
po.observe({type: 'longtask', buffered: true});

Long Animation Frames API

瀏覽器支援

  • Chrome:123。
  • Edge:123。
  • Firefox:不支援。
  • Safari:不支援。

資料來源

Long Animation Frames API 是 Long Tasks API 的新版本,可查看超過 50 毫秒的長時間影格 (而非長時間工作)。這項功能可解決 Long Tasks API 的部分缺點,包括提供更精確的歸因資訊,以及更廣泛的潛在延遲問題範圍。

如要判斷何時會出現長時間的畫面,您可以使用 PerformanceObserver,並註冊觀察 long-animation-frame 類型的項目:

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Log the entry and all associated details.
    console.log(entry.toJSON());
  }
});

// Start listening for `long-animation-frame` entries to be dispatched.
po.observe({type: 'long-animation-frame', buffered: true});

Element Timing API

瀏覽器支援

  • Chrome:77。
  • Edge:79。
  • Firefox:不支援。
  • Safari:不支援。

資料來源

最大內容繪製 (LCP) 指標可用於瞭解最大圖片或文字區塊繪製到畫面上的時間,但在某些情況下,您可能需要評估其他元素的算繪時間。

在這種情況下,請使用 Element Timing API。LCP API 實際上是建構在 Element Timing API 之上,並會自動回報最大的含有內容元素,但您也可以明確為其他元素新增 elementtiming 屬性,並註冊 PerformanceObserver 來觀察 element 項目類型,以便回報其他元素。

<img elementtiming="hero-image" />
<p elementtiming="important-paragraph">This is text I care about.</p>
<!-- ... -->

<script>
  const po = new PerformanceObserver((entryList) => {
    for (const entry of entryList.getEntries()) {
      // Log the entry and all associated details.
      console.log(entry.toJSON());
    }
  });

  // Start listening for `element` entries to be dispatched.
  po.observe({type: 'element', buffered: true});
</script>

Event Timing API

瀏覽器支援

  • Chrome:76。
  • Edge:79。
  • Firefox:89。
  • Safari:不支援。

資料來源

Interaction to Next Paint (INP) 指標會觀察網頁生命週期內的所有點擊、輕觸和鍵盤互動,評估網頁的整體回應速度。網頁的 INP 通常是指互動完成所需的時間最長,從使用者啟動互動到瀏覽器繪製下一個影格,顯示使用者輸入內容的視覺結果。

Event Timing API 可讓您使用 INP 指標。這個 API 會公開事件生命週期內發生的多個時間戳記,包括:

  • startTime:瀏覽器收到事件的時間。
  • processingStart:瀏覽器可開始處理事件事件處理常式時的時間。
  • processingEnd:瀏覽器完成執行此事件事件處理常式啟動的所有同步程式碼的時間。
  • duration:從瀏覽器收到事件到執行事件處理常式啟動的所有同步程式碼完成後,瀏覽器能夠繪製下一個影格之間的時間 (以安全起見,會四捨五入至 8 毫秒)。

以下範例說明如何使用這些值建立自訂評估指標:

const po = new PerformanceObserver((entryList) => {
  // Get the last interaction observed:
  const entries = Array.from(entryList.getEntries()).forEach((entry) => {
    // Get various bits of interaction data:
    const inputDelay = entry.processingStart - entry.startTime;
    const processingTime = entry.processingEnd - entry.processingStart;
    const presentationDelay = entry.startTime + entry.duration - entry.processingEnd;
    const duration = entry.duration;
    const eventType = entry.name;
    const target = entry.target || "(not set)"

    console.log("----- INTERACTION -----");
    console.log(`Input delay (ms): ${inputDelay}`);
    console.log(`Event handler processing time (ms): ${processingTime}`);
    console.log(`Presentation delay (ms): ${presentationDelay}`);
    console.log(`Total event duration (ms): ${duration}`);
    console.log(`Event type: ${eventType}`);
    console.log(target);
  });
});

// A durationThreshold of 16ms is necessary to include more
// interactions, since the default is 104ms. The minimum
// durationThreshold is 16ms.
po.observe({type: 'event', buffered: true, durationThreshold: 16});

Resource Timing API

瀏覽器支援

  • Chrome:29。
  • Edge:12。
  • Firefox:35。
  • Safari:11。

資料來源

Resource Timing API 可讓開發人員深入瞭解特定網頁的資源載入方式。雖然這個 API 的名稱是「Timing」,但提供的資訊不限於時間資料 (雖然有許多這類資料)。您可以存取的其他資料包括:

  • initiatorType:資源的擷取方式,例如從 <script><link> 標記,或是從 fetch() 呼叫擷取。
  • nextHopProtocol:用於擷取資源的通訊協定,例如 h2quic
  • encodedBodySize/decodedBodySize:資源以編碼或解碼形式的大小 (分別為)
  • transferSize:透過網路實際傳輸的資源大小。如果資源是由快取滿足,這個值可能會比 encodedBodySize 小得多,在某些情況下甚至可能為零 (如果不需要重新驗證快取)。

您可以使用資源時間資訊項目的 transferSize 屬性,評估快取命中率指標或快取資源總大小指標,這有助於瞭解資源快取策略對回訪訪客成效的影響。

以下範例會記錄網頁要求的所有資源,並指出每項資源是否由快取滿足。

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // If transferSize is 0, the resource was fulfilled using the cache.
    console.log(entry.name, entry.transferSize === 0);
  }
});

// Start listening for `resource` entries to be dispatched.
po.observe({type: 'resource', buffered: true});

瀏覽器支援

  • Chrome:57。
  • Edge:12。
  • Firefox:58。
  • Safari:15。

資料來源

Navigation Timing API 與 Resource Timing API 類似,但只會回報導覽要求navigation 輸入類型也與 resource 輸入類型相似,但包含一些僅適用於導覽要求的額外資訊 (例如 DOMContentLoadedload 事件觸發時的資訊)。

許多開發人員會追蹤這項指標,以瞭解伺服器回應時間 (第 1 個位元組時間 (TTFB)),您可以使用 Navigation Timing API 查看這項指標,具體來說,就是項目的 responseStart 時間戳記。

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // If transferSize is 0, the resource was fulfilled using the cache.
    console.log('Time to first byte', entry.responseStart);
  }
});

// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});

使用 Service Worker 的開發人員可能會關心另一個指標,也就是導覽要求的 Service Worker 啟動時間。這是指瀏覽器啟動服務工作者執行緒所需的時間,啟動後才能開始攔截擷取事件。

您可以根據 entry.responseStartentry.workerStart 之間的差異,判斷特定導覽要求的服務工作站啟動時間。

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    console.log('Service Worker startup time:',
        entry.responseStart - entry.workerStart);
  }
});

// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});

Server Timing API

瀏覽器支援

  • Chrome:65。
  • Edge:79。
  • Firefox:61。
  • Safari:16.4。

資料來源

Server Timing API 可讓您透過回應標頭,將要求專屬的時間資料從伺服器傳遞至瀏覽器。舉例來說,您可以指出為特定要求在資料庫中查詢資料所需的時間,這有助於偵錯因伺服器速度緩慢而導致的效能問題。

如果開發人員使用第三方數據分析供應商,則只有使用 Server Timing API,才能將伺服器效能資料與這些數據分析工具可能會評估的其他業務指標建立關聯。

如要在回應中指定伺服器時間資料,您可以使用 Server-Timing 回應標頭。以「Black cat ate the mouse」

HTTP/1.1 200 OK

Server-Timing: miss, db;dur=53, app;dur=47.2

接著,您可以在網頁中讀取 Resource Timing API 和 Navigation Timing API 的 resourcenavigation 項目中的這項資料。

// Create the performance observer.
const po = new PerformanceObserver((list) => {
  for (const entry of list.getEntries()) {
    // Logs all server timing data for this response
    console.log('Server Timing', entry.serverTiming);
  }
});

// Start listening for `navigation` entries to be dispatched.
po.observe({type: 'navigation', buffered: true});