性能数据

Performance API 测量并公开可为您的 Web 应用程序收集的性能指标。它提供了观察应用程序性能各个方面的方法。它不提供性能数据分析或可视化。然而,Performance API 与浏览器中的开发者工具集成良好,其数据通常会发送到分析端点和库,以记录有助于您评估数据以找出影响用户性能瓶颈的性能指标。

本页面提供了关于存在哪些 Performance API 数据、如何收集这些数据以及如何访问这些数据的概述。

收集数据

Performance API 公开的大多数指标都会由浏览器自动收集,您无需告诉它去收集:只需检索即可。

某些指标确实需要您告诉浏览器要测量什么

  • Element Timing 指标测量加载和渲染特定 DOM 元素所需的时间。此指标需要选择加入:要要求浏览器包含特定元素的指标,您必须为其添加 elementtiming 属性。
  • User Timing 指标使您能够测量程序中任意两点之间的时间,这些点可能对应于应用程序定义的事务(例如用户登录)。要收集这些指标,您需要在相关点添加 Performance API 调用。
  • Server Timing 指标使您能够测量应用程序定义的服务器端事务所需的时间。要收集这些指标,您的服务器必须发送 Server-Timing HTTP 标头。

性能数据结构

使用 Performance API,您可以在 WindowWorker 的全局上下文中收集性能数据。如果您正在为多个上下文收集性能指标,请查看 performance.timeOrigin 以同步不同上下文的时间起点。

在这些上下文中,单个性能数据由性能条目表示。

性能条目

单个记录的性能数据点称为*性能条目*,它由 PerformanceEntry 接口的实例表示。

Performance API 记录各种不同类型的性能数据,而 PerformanceEntry 有一个 entryType 属性,它是一个描述此性能条目类型的字符串

  • "element" 记录元素加载和渲染所需的时间。
  • "event" 记录浏览器响应事件触发器开始运行事件处理程序所需的时间,以及事件处理程序运行所需的时间。用于测量 下次绘制交互
  • "first-input" 记录 首次输入延迟
  • "largest-contentful-paint" 记录页面加载期间最大的绘制。
  • "layout-shift" 记录每个动画帧中页面布局移动了多少的度量。
  • "longtask" 记录耗时 50 毫秒或更长的任务。
  • "mark" 记录开发者创建的自定义时间戳。
  • "measure" 记录开发者创建的两个时间戳之间的自定义测量。
  • "navigation" 记录与导航到页面和页面初始加载相关的指标。
  • "paint" 记录页面加载期间渲染的关键时刻。
  • "resource" 记录浏览器获取资源所需的时间。
  • "visibility-state" 记录页面可见状态更改的时间,即选项卡从前台切换到后台或反之亦然。

性能条目子类

特定的条目类型通常包含额外的特定类型数据:例如,"resource" 类型捕获 DNS 查找开始和结束的时间。因此,条目由扩展基本 PerformanceEntry 接口的子类表示。例如,"resource" 条目由 PerformanceResourceTiming 接口的实例表示,该接口继承自 PerformanceEntry,并添加了用于记录 DNS 查找时间戳的属性。

PerformanceEntry 的子类也定义了 PerformanceEntry 本身属性的语义:例如,PerformanceEntry 有一个 name 属性,其含义取决于子类。

以下接口继承自 PerformanceEntry

访问数据

您可以通过两种方式访问性能条目。首选方式是使用 PerformanceObserver 接口,该接口使用一个回调函数进行构造,当记录特定性能条目时调用该函数。然后调用其 observe 方法,传入要观察的类型,并使用 buffered 选项来检索在观察之前发生的条目。

js
function logEventDuration(entries) {
  const events = entries.getEntriesByType("event");
  for (const event of events) {
    console.log(
      `Event handler took: ${
        event.processingEnd - event.processingStart
      } milliseconds`,
    );
  }
}

const observer = new PerformanceObserver(logEventDuration);
observer.observe({ type: "event", buffered: true });

或者,您可以使用 Performance.getEntries()Performance.getEntriesByName()Performance.getEntriesByType() 方法来检索页面上的所有性能条目,或者检索与给定名称或类型匹配的条目。

js
const events = performance.getEntriesByType("event");

for (const event of events) {
  console.log(
    `Event handler took: ${
      event.processingEnd - event.processingStart
    } milliseconds`,
  );
}

PerformanceObserver 选项更受青睐,因为

  • getEntries* 方法将始终返回自时间轴开始以来所有相关的条目,因此如果您调用它两次,您将再次看到相同的条目,并且需要过滤掉您之前看到的条目。
  • 观察者通知是异步传递的,因此浏览器可以在空闲时间分派它们,以最大限度地减少其性能影响。
  • 并非所有条目类型都与 getEntries* 方法一起使用。对于某些条目,您必须使用性能观察者来访问它们。

管理缓冲区大小

每个全局对象都有一个性能条目的缓冲区限制。它确保浏览器在持有性能数据时不会消耗无限内存。特别是当您的网站或应用程序获取大量资源时(例如,在使用轮询时),您可能需要查看缓冲区的限制。

entryType 标识符 接口 最大缓冲区条目数
"mark" PerformanceMark 无限
"measure" PerformanceMeasure 无限
"navigation" PerformanceNavigationTiming 无限
"resource" PerformanceResourceTiming 250(可调,见下文)
"longtask" PerformanceLongTaskTiming 200
"paint" PerformancePaintTiming 2(不会更多)
"element" PerformanceElementTiming 150
"event" PerformanceEventTiming 150
"first-input" PerformanceEventTiming 1(不会更多)
"layout-shift" LayoutShift 150
"largest-contentful-paint" LargestContentfulPaint 150
"visibility-state" VisibilityStateEntry 50

表 1. 缓冲区大小(来源)。

对于 "resource" 条目类型,请参阅 管理资源缓冲区大小,了解如何设置不同的缓冲区大小。

对于 "first-input""paint",限制是指标定义固有的。条目不会超过一个(或两个)。

PerformanceObserver 的回调函数包含一个可选的 droppedEntriesCount 参数,它告诉您由于缓冲区存储已满而丢失了多少条目。

js
function perfObserver(list, observer, droppedEntriesCount) {
  list.getEntries().forEach((entry) => {
    // do something with the entries
  });
  if (droppedEntriesCount > 0) {
    console.warn(
      `${droppedEntriesCount} entries were dropped because the buffer was full.`,
    );
  }
}
const observer = new PerformanceObserver(perfObserver);
observer.observe({ type: "resource", buffered: true });

另一个有用的方法是 PerformanceObserver.takeRecords(),它返回性能观察者中存储的性能条目列表,同时清空它。

JSON 数据

所有性能条目都提供了一个 toJSON() 序列化器,它返回条目的 JSON 表示形式。如果您想收集所有可用数据并将其存储在某处,这会很有用。

js
const observer = new PerformanceObserver((list) => {
  list.getEntries().forEach((entry) => {
    console.log(entry.toJSON());
  });
});

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

这将记录一个类似如下的 JSON 对象

json
{
  "name": "dragover",
  "entryType": "event",
  "startTime": 67090751.599999905,
  "duration": 128,
  "processingStart": 67090751.70000005,
  "processingEnd": 67090751.900000095,
  "cancelable": true
}

要获取条目的字符串表示形式,您可以直接对任何 PerformanceEntry 对象使用 JSON.stringify(entry);它会自动调用条目的 toJSON() 方法。

另见