深入理解 Performance API

Avatar of Preethi
Preethi

DigitalOcean 为您旅程的各个阶段提供云产品。 立即开始使用 $200 免费积分!

JavaScript 的 Performance API 是明智的,因为它提供了工具来准确地测量网页的性能,尽管网页的性能很早就被测量了,但它从未变得足够容易或精确。

也就是说,开始使用 API 并不像实际使用它那样容易。 虽然我在其他文章中看到过对它的扩展,但将所有内容联系在一起的整体画面很难找到。

浏览任何解释全局 performance 接口(访问 Performance API 的入口点)的文档,您都会受到一系列其他规范的轰炸,包括高精度时间 API、Performance Timeline API 和 Navigation API,这些规范在众多规范中,让人感到无所适从。 这足以让整体概念变得比平时更令人困惑,即 API 到底测量的是什么,但更重要的是,它很容易忽略我们从中获得的特定好东西。

这是一个关于所有这些部分如何组合在一起的插图。 这可能会非常混乱,因此,拥有一个视觉效果可以帮助阐明我们正在讨论的内容。

Performance API 包含 Performance Timeline API,它们共同构成了广泛的方法,用于获取关于网页性能的有用指标。

让我们深入研究一下,好吗?

高精度时间 API

performance 接口是 高精度时间 API 的一部分。

您可能会问“什么是高精度时间?”。 这是一个我们不能忽视的关键概念。

基于 Date 的时间精确到毫秒。 另一方面,高精度时间精确到毫秒的几分之一。 这非常精确,使其更适合于产生精确的时间测量结果。

值得指出的是,由 用户代理 (UA) 测量的,高精度时间不会随着系统时间的任何更改而更改,因为它来自 UA 创建的全局、单调递增的时钟。 时间始终增加,不能被强制减少。 这成为时间测量的有用约束。

Performance API 中测量的每次时间测量都是高精度时间。 这不仅使其成为测量性能的超精确方法,而且也是它成为高精度时间 API 的一部分 的原因,以及为什么我们经常看到这两个 API 同时提及。

Performance Timeline API

Performance Timeline API 是 Performance API 的扩展。 这意味着,Performance API 是高精度时间 API 的一部分,而 Performance Timeline API 是 Performance API 的一部分。

或者,更简洁地说

High Resolution Time API
└── Performance API
    └── Performance Timeline API

Performance Timeline API 使我们可以访问从整个 Performance API 本身获得的几乎所有测量值和指标。 这是我们触手可及的大量信息,只有一个 API,这就是为什么本文开头图表将它们几乎放在同一个平面上。

Performance API 有许多扩展。 每个扩展都返回与性能相关的条目,并且所有这些条目都可以通过 Performance Timeline 访问甚至进行过滤,这使其成为任何想要开始进行性能测量的人必须学习的 API。 它们的关系如此密切并且互补,因此熟悉这两者是有意义的。

以下是 Performance Timeline API 的三种方法,这些方法包含在 performance 接口中

  • getEntries()
  • getEntriesByName()
  • getEntriesByType()

每种方法都返回一个(可选过滤的)性能条目列表,这些条目从 Performance API 的所有其他扩展中收集而来,在我们继续的过程中,我们将更加熟悉它们。

API 中包含的另一个关键接口是 PerformanceObserver。 它监控给定性能条目列表中的新条目,并发出通知。 对实时监控非常有用!

性能条目

我们使用 Performance API 测量的指标称为“条目”,它们都提供了很多关于网页性能的见解。

好奇它们是什么吗? MDN 有一个 完整列表,该列表可能会随着新项目的发布而更新,但这是我们目前拥有的内容

条目 它测量的指标 父 API
frame 测量帧,帧代表浏览器需要完成一项工作循环的量,以处理诸如 DOM 事件、调整大小、滚动和 CSS 动画之类的事情。 Frame Timing API
mark 在性能时间线中创建一个时间戳,为名称、开始时间和持续时间提供值。 User Timing API
measure 类似于 mark,因为它们是时间线上的点,但它们是为您命名的,并放置在标记之间。 基本上,它们是标记之间的中间点,没有自定义名称值。 User Timing API
navigation 为加载操作提供上下文,例如发生的事件类型。 Navigation Timing API
paint 报告像素在屏幕上渲染的时刻,例如第一次绘制、第一次绘制有内容、开始时间和总持续时间。 Paint Timing API
resource 测量渲染屏幕的依赖项的延迟,如图像、脚本和样式表。 这就是缓存发挥作用的地方! Resource Timing API

让我们看几个例子,说明每个 API 在使用中的样子。 要深入了解它们,您可以查看上面表格中链接的规范。 Frame Timing API 仍在开发中。

Paint Timing API 已经很方便地 在 CSS-Tricks 上进行了详细的介绍,但以下是如何提取开始绘制时间戳的示例

// Time when the page began to render 
console.log(performance.getEntriesByType('paint')[0].startTime)

User Timing API 可以测量开发人员脚本的性能。 例如,假设您有一段代码用于验证上传的文件。 我们可以测量执行该操作所需的时间

// Time to console-print "hello"
// We could also make use of "performance.measure()" to measure the time
// instead of calculating the difference between the marks in the last line.
performance.mark('')
console.log('hello')
performance.mark('')
var marks = performance.getEntriesByType('mark')
console.info(`Time took to say hello ${marks[1].startTime - marks[0].startTime}`)

Navigation Timing API 显示加载当前页面的指标,甚至包括先前页面卸载时的指标。 我们可以用极高的精度来测量当前页面到底加载了多长时间

// Time to complete DOM content loaded event
var navEntry = performance.getEntriesByType('navigation')[0]
console.log(navEntry.domContentLoadedEventEnd - navEntry.domContentLoadedEventStart)

Resource Timing API 与 Navigation Timing API 类似,它测量加载时间,只是它测量加载当前页面所有资源(而不是当前页面本身)的指标。 例如,我们可以测量托管在另一个服务器(如 CDN)上的图像在页面上加载所需的时间

// Response time of resources
performance.getEntriesByType('resource').forEach((r) => {
console.log(`response time for ${r.name}: ${r.responseEnd - r.responseStart}`);
});

导航异常

想听听关于 Navigation Timing API 的一个有趣的小知识吗?

它是 Performance Timeline API 之前构思的。 这就是为什么,虽然您可以使用 Performance Timeline API 访问一些导航指标(通过过滤 navigation 条目类型),但 Navigation Timing API 本身有两个接口直接从 Performance API 扩展而来

  • performance.timing
  • performance.navigation

performance.navigation 提供的所有指标都可以由 Performance Timeline API 的 navigation 条目提供。 然而,对于您从 performance.timing 获取的指标,只有部分指标可以通过 Performance Timeline API 访问。

因此,我们使用 performance.timing 获取当前页面的导航指标,而不是通过 performance.getEntriesByType("navigation") 使用 Performance Timeline API

// Time from start of navigation to the current page to the end of its load event
addEventListener('load', () => {
	with(performance.timing) 
		console.log(navigationStart - loadEventEnd);
})

总结

我认为,开始使用 Performance API 的最佳方法是从熟悉所有性能条目类型及其属性开始。 这将使您快速熟悉所有 API 的最终结果,以及该 API 在测量性能方面提供的强大功能。

作为第二个行动步骤,了解 Performance Timeline API 如何探测所有这些可用的指标。 正如我们所述,这两者密切相关,它们之间的相互作用可以打开有趣且有用的测量方法。

在这一点上,您可以开始掌握熟练使用其他扩展 API 的艺术。 这就是所有内容汇集在一起的地方,您最终可以看到所有这些 API、方法和条目如何相互关联。