性能数据

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

此页面概述了哪些类型的性能 API 数据存在、如何收集以及如何访问。

收集数据

性能 API 公开的大多数指标都是由浏览器自动收集的,您无需告诉它收集这些指标:您只需检索它们即可。

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

  • 元素计时 指标衡量加载和渲染某些 DOM 元素所需的时间。此指标是选择加入的:要请求浏览器包含特定元素的指标,您必须向其添加 elementtiming 属性。
  • 用户计时 指标使您能够测量程序中任意点之间的时间,这些点可能映射到应用程序定义的操作(例如登录用户)。要收集这些指标,您需要在相关点添加性能 API 调用。
  • 服务器计时 指标使您能够测量应用程序定义的服务器端操作所花费的时间。要收集这些指标,您的服务器必须发送 Server-Timing HTTP 标头。

性能数据结构

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

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

性能条目

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

性能 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",限制是指标定义中固有的。条目不会多于一个(或两个)。

性能观察器回调 包含一个可选的 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() 方法。

另请参阅