PerformanceEventTiming

事件计时 API 的 PerformanceEventTiming 接口提供了对由用户交互触发的某些事件类型的延迟的见解。

描述

此 API 通过为某些事件类型提供事件时间戳和持续时间(参见下文)来使缓慢事件可见。例如,您可以监视用户操作与其事件处理程序开始之间的时间,或事件处理程序运行所需的时间。

此 API 特别适用于测量 首次输入延迟 (FID):从用户首次与您的应用程序交互的时刻到浏览器实际能够响应该交互的时刻之间的时间。

您通常通过创建 PerformanceObserver 实例,然后调用其 observe() 方法(将 "event""first-input" 作为 type 选项的值传递)来使用 PerformanceEventTiming 对象。然后,PerformanceObserver 对象的回调将使用 PerformanceEventTiming 对象列表调用,您可以分析这些对象。有关更多信息,请参见 下面的示例

默认情况下,PerformanceEventTiming 条目在其 duration 为 104 毫秒或更大时公开。研究表明,在 100 毫秒内未处理的用户输入被认为是缓慢的,而 104 毫秒是大于 100 毫秒的 8 的第一个倍数(出于安全原因,此 API 四舍五入到最接近的 8 毫秒倍数)。但是,您可以使用 observe() 方法中 durationThreshold 选项将 PerformanceObserver 设置为不同的阈值。

此接口从其父级 PerformanceEntry 继承方法和属性

PerformanceEntry PerformanceEventTiming

公开的事件

事件计时 API 公开以下事件类型

点击事件 auxclickclickcontextmenudblclick
组合事件 compositionendcompositionstartcompositionupdate
拖放事件 dragenddragenterdragleavedragoverdragstartdrop
输入事件 beforeinputinput
键盘事件 keydownkeypresskeyup
鼠标事件 mousedownmouseentermouseleavemouseoutmouseovermouseup
指针事件 pointeroverpointerenterpointerdownpointeruppointercancelpointeroutpointerleavegotpointercapturelostpointercapture
触摸事件 touchstarttouchendtouchcancel

请注意,以下事件未包含在列表中,因为它们是连续事件,并且目前无法获得有意义的事件计数或性能指标:mousemovepointermovepointerrawupdatetouchmovewheeldrag

要获取所有公开事件的列表,您也可以在 performance.eventCounts 映射中查找键

js
const exposedEventsList = [...performance.eventCounts.keys()];

构造函数

此接口本身没有构造函数。有关如何通常获取 PerformanceEventTiming 接口保存的信息,请参见 下面的示例

实例属性

此接口通过以下方式扩展了以下 PerformanceEntry 属性,用于事件计时性能条目类型

PerformanceEntry.duration 只读

返回一个 DOMHighResTimeStamp,表示从 startTime 到下一个渲染绘制的时间(四舍五入到最接近的 8 毫秒)。

PerformanceEntry.entryType 只读

返回 "event"(对于长事件)或 "first-input"(对于第一次用户交互)。

PerformanceEntry.name 只读

返回关联事件的类型。

PerformanceEntry.startTime 只读

返回一个表示关联事件的 DOMHighResTimeStamptimestamp 属性。 这是事件创建的时间,可以看作用户交互发生时间的代理。

此接口还支持以下属性

PerformanceEventTiming.cancelable 只读

返回关联事件的 cancelable 属性。

PerformanceEventTiming.interactionId 只读 实验性

返回唯一标识触发关联事件的用户交互的 ID。

PerformanceEventTiming.processingStart 只读

返回一个表示事件调度开始时间的 DOMHighResTimeStamp。 要衡量用户操作时间与事件处理程序开始运行时间之间的间隔,请计算 processingStart-startTime

PerformanceEventTiming.processingEnd 只读

返回一个表示事件调度结束时间的 DOMHighResTimeStamp。 要衡量事件处理程序运行时间,请计算 processingEnd-processingStart

PerformanceEventTiming.target 只读

如果关联事件的最后一个目标没有被移除,则返回它。

实例方法

PerformanceEventTiming.toJSON()

返回 PerformanceEventTiming 对象的 JSON 表示。

示例

获取事件计时信息

要获取事件计时信息,请创建一个 PerformanceObserver 实例,然后调用其 observe() 方法,并将 "event""first-input" 作为 type 选项的值传入。 您还需要将 buffered 设置为 true 以获取用户代理在构建文档时缓冲的事件。 然后,PerformanceObserver 对象的回调将被调用,并带有一个 PerformanceEventTiming 对象列表,您可以分析这些对象。

js
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    // Full duration
    const duration = entry.duration;

    // Input delay (before processing event)
    const delay = entry.processingStart - entry.startTime;

    // Synchronous event processing time
    // (between start and end dispatch)
    const eventHandlerTime = entry.processingEnd - entry.processingStart;
    console.log(`Total duration: ${duration}`);
    console.log(`Event delay: ${delay}`);
    console.log(`Event handler duration: ${eventHandlerTime}`);
  });
});

// Register the observer for events
observer.observe({ type: "event", buffered: true });

您还可以设置不同的 durationThreshold。 默认值为 104 毫秒,最小可能的持续时间阈值为 16 毫秒。

js
observer.observe({ type: "event", durationThreshold: 16, buffered: true });

报告首次输入延迟 (FID)

首次输入延迟或 FID,测量从用户首次与页面交互(例如,当他们单击链接或点击按钮时)到浏览器实际能够开始处理响应该交互的事件处理程序的时间。

js
// Keep track of whether (and when) the page was first hidden, see:
// https://github.com/w3c/page-visibility/issues/29
// NOTE: ideally this check would be performed in the document <head>
// to avoid cases where the visibility state changes before this code runs.
let firstHiddenTime = document.visibilityState === "hidden" ? 0 : Infinity;
document.addEventListener(
  "visibilitychange",
  (event) => {
    firstHiddenTime = Math.min(firstHiddenTime, event.timeStamp);
  },
  { once: true },
);

// Sends the passed data to an analytics endpoint. This code
// uses `/analytics`; you can replace it with your own URL.
function sendToAnalytics(data) {
  const body = JSON.stringify(data);
  // Use `navigator.sendBeacon()` if available,
  // falling back to `fetch()`.
  (navigator.sendBeacon && navigator.sendBeacon("/analytics", body)) ||
    fetch("/analytics", { body, method: "POST", keepalive: true });
}

// Use a try/catch instead of feature detecting `first-input`
// support, since some browsers throw when using the new `type` option.
// https://webkit.org/b/209216
try {
  function onFirstInputEntry(entry) {
    // Only report FID if the page wasn't hidden prior to
    // the entry being dispatched. This typically happens when a
    // page is loaded in a background tab.
    if (entry.startTime < firstHiddenTime) {
      const fid = entry.processingStart - entry.startTime;

      // Report the FID value to an analytics endpoint.
      sendToAnalytics({ fid });
    }
  }

  // Create a PerformanceObserver that calls
  // `onFirstInputEntry` for each entry.
  const po = new PerformanceObserver((entryList) => {
    entryList.getEntries().forEach(onFirstInputEntry);
  });

  // Observe entries of type `first-input`, including buffered entries,
  // i.e. entries that occurred before calling `observe()` below.
  po.observe({
    type: "first-input",
    buffered: true,
  });
} catch (e) {
  // Do nothing if the browser doesn't support this API.
}

规范

规范
事件计时 API
# sec-performance-event-timing

浏览器兼容性

BCD 表仅在浏览器中加载

另请参见