用户计时

用户时序(User Timing)是性能 API (Performance API) 的一部分,它允许你使用浏览器性能时间轴中的高精度时间戳来测量应用程序的性能。有两种类型的性能时序条目:

什么是用户时序?

浏览器会为你提供某些信息(称为性能条目),并将其添加到浏览器的性能时间轴中。例如,这包括 资源时序 API 提供的条目,它们用于确定获取图像等资源所需的时间。

然而,浏览器无法确定你的应用程序内部发生了什么。例如,当用户点击按钮或在你应用程序中执行特定任务时,没有高精度性能测量。用户时序 API 是浏览器性能时间轴的扩展,它帮助你测量和记录应用程序特有的性能数据。

与调用 Date.now()performance.now() 相比,使用此 API 的优势在于你可以为标记命名,并且它能与性能工具很好地集成。浏览器的开发者工具可以在“性能”面板中显示性能标记,并且它还能与 PerformanceObserver 对象等其他性能 API 一起使用。

添加性能标记

要开始测量应用程序功能性能的第一步,你需要为代码中的重要位置添加命名的性能标记。理想情况下,你应该遍历代码库,确定关键路径和你希望确保其能够快速执行的重要任务。

performance.mark() 方法用于创建 PerformanceMark。该方法接受一个参数,即标记的 name,如下例所示。

js
// Place at a location in the code that starts login
performance.mark("login-started");

// Place at a location in the code that finishes login
performance.mark("login-finished");

如果 name 参数不够,mark() 可以通过一个选项对象进行配置,你可以在其中将额外信息放入 detail 属性中,该属性可以是任何类型。如果需要,你还可以设置一个不同的 startTime。在下面的代码中,startTime 被设置为 12.5,并且通过 detail 提供了额外信息,例如使用的 HTML 元素。

js
performance.mark("login-started", {
  startTime: 12.5,
  detail: { htmlElement: myElement.id },
});

测量标记之间的时间

现在你已经在应用程序中添加了标记,可以测量它们之间的时间了。

Performance.measure() 方法用于创建 PerformanceMeasure 对象。它接受一个 name 参数(用于标识测量值)以及两个标记 startend,它将在此之间进行测量。下面的示例创建了一个 "login-duration" 测量,并测量了登录过程的开始到结束之间的时间。

该对象随后有一个 duration 属性,它会为你计算结束标记时间戳减去开始标记时间戳。例如,你可以记录此值或将其发送到某个分析端点。

js
const loginMeasure = performance.measure(
  "login-duration",
  "login-started",
  "login-finished",
);

console.log(loginMeasure.duration);

Performance.measure() 方法也可以通过选项对象进行配置,因此你可以进行更高级的测量或使用 detail 属性提供额外信息。

例如,你可以使用 click 事件中的 event.timestamp 属性,确切了解用户何时点击了登录按钮,并将其测量到 UI 更新的时间点,也就是这里的 "login-finished" 标记。

js
loginButton.addEventListener("click", (clickEvent) => {
  fetch(loginURL).then((data) => {
    renderLoggedInUser(data);

    const marker = performance.mark("login-finished");

    performance.measure("login-click", {
      detail: { htmlElement: myElement.id },
      start: clickEvent.timeStamp,
      end: marker.startTime,
    });
  });
});

观察性能测量

获取自定义性能测量通知的首选方法是使用 PerformanceObserver 对象。性能观察器允许你被动地订阅性能标记和测量值的发生。

js
function perfObserver(list, observer) {
  list.getEntries().forEach((entry) => {
    if (entry.entryType === "mark") {
      console.log(`${entry.name}'s startTime: ${entry.startTime}`);
    }
    if (entry.entryType === "measure") {
      console.log(`${entry.name}'s duration: ${entry.duration}`);
    }
  });
}
const observer = new PerformanceObserver(perfObserver);
observer.observe({ entryTypes: ["measure", "mark"] });

更多信息,请参阅 PerformanceObserver

检索标记和测量

浏览器的性能时间轴中有许多不同的性能条目。有些由浏览器添加,有些则可能由你添加,例如上面示例中的登录标记和测量值。

要在单个时间点检索性能标记和测量值,Performance 接口提供了三个方法,如下所示。

注意: 以下方法不会通知你新的性能标记;你只会获得在调用这些方法时已创建的标记。有关使用 PerformanceObserver 接收新指标可用通知的信息,请参阅上面的 观察性能测量 部分。通常,使用性能观察器是获取性能标记和测量值的首选方法。

performance.getEntries() 方法获取所有性能条目。你可以根据需要进行过滤。

js
const entries = performance.getEntries();
entries.forEach((entry) => {
  if (entry.entryType === "mark") {
    console.log(`${entry.name}'s startTime: ${entry.startTime}`);
  }
  if (entry.entryType === "measure") {
    console.log(`${entry.name}'s duration: ${entry.duration}`);
  }
});

performance.getEntriesByType(entryType) 方法会按类型过滤条目。

js
const marks = performance.getEntriesByType("mark");
marks.forEach((entry) => {
  console.log(`${entry.name}'s startTime: ${entry.startTime}`);
});

const measures = performance.getEntriesByType("measure");
measures.forEach((entry) => {
  console.log(`${entry.name}'s duration: ${entry.duration}`);
});

performance.getEntriesByName(name, entryType) 方法允许你按名称获取特定的标记或测量值。

js
// Log all marks named "debug-marks"
const debugMarks = performance.getEntriesByName("debug-mark", "mark");
debugMarks.forEach((entry) => {
  console.log(`${entry.name}'s startTime: ${entry.startTime}`);
});

移除标记和测量

要清理所有性能标记或测量值,或仅清理特定条目,可以使用以下方法:

js
// Clear all marks
performance.clearMarks();

// Removes the marker with the name "myMarker"
performance.clearMarks("myMarker");

// Clear all measures
performance.clearMeasures();

// Removes the measure with the name "myMeasure"
performance.clearMeasures("myMeasure");

另见