高精度计时
Performance API 允许进行基于时间的、可能具有亚毫秒级分辨率的高精度测量,并且具有稳定的单调时钟,不受系统时钟偏差或调整的影响。为了进行精确的基准测试,需要高分辨率计时器,而不是精度较低且非单调的 Date 时间戳。
本文档概述了 Performance API 中的高精度时间工作原理,以及它与 Date 时间戳的对比。
DOMHighResTimeStamp
高精度计时是通过使用 DOMHighResTimeStamp 类型来表示时间值实现的。单位是毫秒,应精确到 5 微秒 (µs)。然而,如果浏览器无法提供精确到 5 微秒的时间值,则可以将该值表示为精确到毫秒的时间。这可能是由于硬件/软件限制、安全和隐私原因造成的。有关更多信息,请参阅下面的 降低精度 部分。
Performance API 中的所有时间戳都使用 DOMHighResTimeStamp 类型。以前,Performance API(以及其他 Web API)使用的是 EpochTimeStamp 类型(以前称为 DOMTimeStamp)。现在不推荐使用这些类型。
Performance.now() vs. Date.now()
JavaScript 将 Date.now() 定义为自 纪元 以来的毫秒数,纪元定义为 1970 年 1 月 1 日午夜(UTC)。另一方面,performance.now() 方法是相对于 Performance.timeOrigin 属性的。有关更多信息,请参阅下面的 时间起点 部分。
JavaScript Date 时间会受到系统时钟偏差或调整的影响。这意味着时间值可能不总是单调递增的。Date 对象的主要目的是向用户显示时间和日期信息,因此许多操作系统会运行一个定期同步时间的守护进程。时钟可能每小时被调整几次,每次几毫秒。
performance.now() 方法(以及所有其他 DOMHighResTimeStamp 值)提供单调递增的时间值,不受时钟调整的影响。这意味着 DOMHighResTimeStamp 值保证至少等于您上次访问它时的时间,甚至大于它。
Date.now(); // 1678889977578
performance.now(); // 233936
对于性能测量、精确计算帧率 (FPS)、动画循环等,请使用 Performance.now() 提供的单调递增的高分辨率时间,而不是 JavaScript 的 Date.now()。
总结
| - | Performance.now() |
Date.now() |
|---|---|---|
| 分辨率 | 亚毫秒 | milliseconds |
| Origin | Performance.timeOrigin |
Unix 纪元(1970 年 1 月 1 日 UTC) |
| 使用时钟调整 | 否 | 是 |
| 单调递增 | 是 | 否 |
时间起点
Performance API 使用 Performance.timeOrigin 属性来确定与性能相关的计时器的基线。所有 DOMHighResTimeStamp 时间都相对于 timeOrigin 属性。
在 Window 上下文中,此时间起点是导航开始的时间。在 Worker 和 ServiceWorker 上下文中,时间起点是 worker 运行的时间。
在以前的规范版本(Level 1)中,performance.now() 方法过去是相对于导航计时规范中的 performance.timing.navigationStart 属性的。然而,在后来的规范版本(Level 2)中,这一点发生了变化,performance.now() 现在相对于 Performance.timeOrigin,这避免了跨网页比较时间戳时的时钟更改风险。
// Level 1 (clock change risks)
currentTime = performance.timing.navigationStart + performance.now();
// Level 2 (no clock change risks)
currentTime = performance.timeOrigin + performance.now();
同步不同上下文的时间起点
为了考虑窗口和 worker 上下文中不同的时间起点,您应该通过 timeOrigin 属性来转换来自 worker 脚本的时间戳,以便为整个应用程序同步计时。有关同步时间的示例代码,请参阅 Performance.timeOrigin 页面的示例部分。
降低精度
为了提供针对时序攻击和 指纹识别 的保护,DOMHighResTimeStamp 类型会根据站点隔离状态进行粗化。
- 隔离上下文中的分辨率:5 微秒
- 非隔离上下文中的分辨率:100 微秒
要为您的站点应用跨源隔离,请使用 Cross-Origin-Opener-Policy (COOP) 和 Cross-Origin-Embedder-Policy (COEP) 标头。
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
这些标头确保顶级文档不与跨源文档共享浏览上下文组。 Cross-Origin-Opener-Policy 对您的文档进行进程隔离,潜在攻击者无法访问您的全局对象(如果他们在弹出窗口中打开它),从而防止了一系列称为 XS-Leaks 的跨源攻击。