用户计时

W3C 候选推荐草案

关于此文档的更多细节
此版本
https://w3org.cn/TR/2026/CRD-user-timing-20260311/
最新发布版本
https://w3org.cn/TR/user-timing/
最新编辑草案
https://w3c.github.io/user-timing/
历史
https://w3org.cn/standards/history/user-timing
提交历史
测试套件
https://wpt.fyi/results/user-timing
实现报告
https://wpt.fyi/results/user-timing
编辑
Nicolás Peña Moreno (谷歌)
前任编辑
Ilya Grigorik (谷歌)
Jatinder Mann (Microsoft Corp.)(截至 2014 年 2 月)
Zhiheng Wang (Google Inc.)(截至 2013 年 7 月)
Anderson Quach (Microsoft Corp.)(截至 2011 年 3 月)
反馈
GitHub w3c/user-timing拉取请求新问题打开的问题
public-web-perf@w3.org,主题行 [UserTiming]存档
实现
我可以使用用户计时吗?

摘要

本规范定义了一个接口,帮助 Web 开发者通过提供高精度时间戳来测量其应用的性能。

本文档状态

本节描述了本文件发布时的状态。当前的 W3C 出版物列表和本技术报告的最新版本可以在 W3C 标准和草案索引中找到。

此用户计时规范旨在取代 [USER-TIMING-2] 并包括

此文档由 Web 性能工作组 作为候选推荐草案发布,使用 推荐轨道

作为候选推荐标准发布并不意味着得到 W3C 及其成员的认可。候选推荐标准草案整合了来自先前候选推荐标准的更改,工作组打算将其包含在后续的候选推荐标准快照中。

这是一份草案文件,可能随时被其他文件更新、替换或废弃。将其作为进展中的工作以外的引用是不恰当的。

此文档由在 W3C 专利政策 下运作的工作组制作。W3C 维护一份 公开的专利披露列表,该页面同样包含披露专利的说明。任何实际了解认为包含 关键声明 的专利的个人,必须依据 W3C 专利政策第 6 节进行披露。

本文件受 2025 年 8 月 18 日 W3C 流程文档约束。

1. 简介

本节是非规范性的。

Web 开发者需要能够评估并理解其应用的性能特征。虽然 JavaScript [ECMA-262] 提供了一种通过 Date.now() 方法获取当前时间戳来测量应用延迟的机制,但此时间戳的精度在不同用户代理间有所差异。

本文档定义了 PerformanceMarkPerformanceMeasure 接口,以及对 Performance 接口的扩展,这些接口公开了高精度、单调递增的时间戳,使开发者能够更好地测量其应用的性能特性。

下面的脚本演示了开发者如何使用本文档中定义的接口来获取与开发者脚本相关的计时数据。

async function run() {
  performance.mark("startTask1");
  await doTask1(); // Some developer code
  performance.mark("endTask1");

  performance.mark("startTask2");
  await doTask2(); // Some developer code
  performance.mark("endTask2");

  // Log them out
  const entries = performance.getEntriesByType("mark");
  for (const entry of entries) {
    console.table(entry.toJSON());
  }
}
run();

[PERFORMANCE-TIMELINE-2] 定义了两种检索已记录指标的机制:getEntries()getEntriesByType() 方法,以及 PerformanceObserver 接口。前者最适合在单个时间点通过名称检索特定指标,后者则针对在指标可用时接收新指标通知的场景进行了优化。

再举一个例子,设有一个元素,在点击后获取一些新内容并指示已获取完成。我们希望报告用户点击到获取完成之间的时间。不能在点击处理函数执行时标记时间,因为这会漏掉处理事件的延迟,所以改用事件硬件时间戳。同时我们希望知道组件名称,以获得更细致的分析。

element.addEventListener("click", e => {
  const component = getComponent(element);
  fetch(component.url).then(() => {
    element.textContent = "Updated";
    const updateMark = performance.mark("update_component", {
      detail: {component: component.name},
    });
    performance.measure("click_to_update_component", {
      detail: {component: component.name},
      start: e.timeStamp,
      end: updateMark.startTime,
    });
  });
});

2. 一致性

除了标记为非规范性的章节外,本规范中的所有创作指南、图表、示例和注释均为非规范性内容。本规范中的其他所有内容均为规范性内容。

本文件中的关键词 MAYMUST 依据 BCP 14 [RFC2119] [RFC8174] 的解释进行解读,且仅在全部大写出现时才适用,如本文所示。

某些合规性要求以属性、方法或对象的形式表述。这类要求应解释为对用户代理的要求。

本规范中的 IDL 片段 MUST 被解释为符合 Web IDL 规范的必需 IDL 片段。[WEBIDL]

3. 用户计时

3.1 Performance 接口的扩展

The Performance 接口和 DOMHighResTimeStamp 在 [HR-TIME-2] 中定义。PerformanceEntry 接口在 [PERFORMANCE-TIMELINE-2] 中定义。

WebIDLdictionary PerformanceMarkOptions {
    any detail;
    DOMHighResTimeStamp startTime;
};

dictionary PerformanceMeasureOptions {
    any detail;
    (DOMString or DOMHighResTimeStamp) start;
    DOMHighResTimeStamp duration;
    (DOMString or DOMHighResTimeStamp) end;
};

partial interface Performance {
    PerformanceMark mark(DOMString markName, optional PerformanceMarkOptions markOptions = {});
    undefined clearMarks(optional DOMString markName);
    PerformanceMeasure measure(DOMString measureName, optional (DOMString or PerformanceMeasureOptions) startOrMeasureOptions = {}, optional DOMString endMark);
    undefined clearMeasures(optional DOMString measureName);
};

3.1.1 mark() 方法

存储带有关联名称(即 “标记”)的时间戳。它 MUST 运行以下步骤

  1. 运行 PerformanceMark 构造函数 并让 entry 为新创建的对象。
  2. 入队 entry
  3. entry 添加到 性能条目缓冲区
  4. 返回 entry
3.1.1.1 PerformanceMarkOptions 字典
detail
要随标记一起包含的元数据。
startTime
用作标记时间的时间戳。

3.1.2 clearMarks() 方法

移除带有关联名称的已存时间戳。它 MUST 运行以下步骤

  1. 如果省略了 markName,则从 性能条目缓冲区 中移除所有 PerformanceMark 对象。
  2. 否则,移除 性能条目缓冲区name 等于 markName 的所有 PerformanceMark 对象。
  3. 返回 undefined

3.1.3 measure() 方法

存储两次标记之间的 DOMHighResTimeStamp 持续时间以及关联的名称(即 “度量”)。它 MUST 运行以下步骤

  1. 如果 startOrMeasureOptions 是一个 PerformanceMeasureOptions 对象且 startenddurationdetail 中至少有一个 存在,则运行以下检查
    1. 如果提供了 endMark抛出 TypeError
    2. 如果 startOrMeasureOptionsstartend 成员都被省略,则 抛出 TypeError
    3. 如果 startOrMeasureOptionsstartdurationend 成员全部 存在,则 抛出 TypeError
  2. 按如下方式计算 end time
    1. 如果提供了 endMark,则令 end time 为运行 将标记转换为时间戳 算法并传入 endMark 所得到的值。
    2. 否则,若 startOrMeasureOptionsPerformanceMeasureOptions 对象且其 end 成员 存在,则令 end time 为运行 将标记转换为时间戳 算法并传入 startOrMeasureOptionsend 所得到的值。
    3. 否则,若 startOrMeasureOptionsPerformanceMeasureOptions 对象且其 startduration 成员均 存在
      1. start 为运行 将标记转换为时间戳 算法并传入 start 所得到的值。
      2. duration 为运行 将标记转换为时间戳 算法并传入 duration 所得到的值。
      3. end timestartduration
    4. 否则,令 end timePerformance 对象的 now() 方法返回的值。
  3. 按如下方式计算 start time
    1. 如果 startOrMeasureOptionsPerformanceMeasureOptions 对象且其 start 成员 存在,则令 start time 为运行 将标记转换为时间戳 算法并传入 startOrMeasureOptionsstart 所得到的值。
    2. 否则,若 startOrMeasureOptionsPerformanceMeasureOptions 对象且其 durationend 成员均 存在
      1. duration 为运行 将标记转换为时间戳 算法并传入 duration 所得到的值。
      2. end 为运行 将标记转换为时间戳 算法并传入 end 所得到的值。
      3. start timeend 减去 duration
    3. 否则,若 startOrMeasureOptionsDOMString,则令 start time 为运行 将标记转换为时间戳 算法并传入 startOrMeasureOptions 所得到的值。
    4. 否则,令 start time0
  4. 创建一个新的 PerformanceMeasure 对象(entry),并使用 this相关 realm
  5. entryname 属性设为 measureName
  6. entryentryType 属性设为 DOMString "measure"
  7. entrystartTime 属性设为 start time
  8. entryduration 属性设为从 start timeend time 的持续时间。得到的持续时间值 MAY 为负数。
  9. 按如下方式设置 entrydetail 属性
    1. 如果 startOrMeasureOptionsPerformanceMeasureOptions 对象且其 detail 成员 存在
      1. record 为对 startOrMeasureOptionsdetail 调用 StructuredSerialize 算法的结果。
      2. entrydetail 设置为对 record 与当前 realm 调用 StructuredDeserialize 算法的返回值。
    2. 否则,将其设为 null
  10. 入队 entry
  11. entry 添加到 性能条目缓冲区
  12. 返回 entry
3.1.3.1 PerformanceMeasureOptions 字典
detail
要随度量一起包含的元数据。
start
用作起始时间的时间戳或用作起始标记的字符串。
duration
起始时间与结束时间之间的持续时间。
end
用作结束时间的时间戳或用作结束标记的字符串。

3.1.4 clearMeasures() 方法

移除带有关联名称的已存时间戳。它 MUST 运行以下步骤

  1. 如果省略了 measureName,则从 性能条目缓冲区 中移除所有 PerformanceMeasure 对象。
  2. 否则,移除 性能条目缓冲区name 等于 measureName 的所有 PerformanceMeasure 对象。
  3. 返回 undefined

3.2 The PerformanceMark Interface

The PerformanceMark interface also exposes marks created via the Performance interface's mark() method to the Performance Timeline.

WebIDL[Exposed=(Window,Worker)]
interface PerformanceMark : PerformanceEntry {
  constructor(DOMString markName, optional PerformanceMarkOptions markOptions = {});
  readonly attribute any detail;
};

The PerformanceMark interface extends the following attributes of the PerformanceEntry interface

The name attribute must return the mark's name.

The entryType attribute must return the DOMString "mark".

The startTime attribute must return a DOMHighResTimeStamp with the mark's time value.

The duration attribute must return a DOMHighResTimeStamp of value 0.

The PerformanceMark interface contains the following additional attribute

The detail attribute must return the value it is set to (it's copied from the PerformanceMarkOptions dictionary).

3.2.1 The PerformanceMark Constructor

The PerformanceMark constructor must run the following steps

  1. If the current global object is a Window object and markName uses the same name as a read only attribute in the PerformanceTiming interface, throw a SyntaxError.
  2. Create a new PerformanceMark object (entry) with the current global object's realm.
  3. Set entry's name attribute to markName.
  4. Set entry's entryType attribute to DOMString "mark".
  5. Set entry's startTime attribute as follows
    1. If markOptions's startTime member exists, then
      1. If markOptions's startTime is negative, throw a TypeError.
      2. Otherwise, set entry's startTime to the value of markOptions's startTime.
    2. Otherwise, set it to the value that would be returned by the Performance object's now() method.
  6. Set entry's duration attribute to 0.
  7. If markOptions's detail is null, set entry's detail to null.
  8. 否则
    1. Let record be the result of calling the StructuredSerialize algorithm on markOptions's detail.
    2. Set entry's detail to the result of calling the StructuredDeserialize algorithm on record and the current realm.

3.3 The PerformanceMeasure Interface

The PerformanceMeasure interface also exposes measures created via the Performance interface's measure() method to the Performance Timeline.

WebIDL[Exposed=(Window,Worker)]
interface PerformanceMeasure : PerformanceEntry {
  readonly attribute any detail;
};

The PerformanceMeasure interface extends the following attributes of the PerformanceEntry interface

The name attribute must return the measure's name.

The entryType attribute must return the DOMString "measure".

The startTime attribute must return a DOMHighResTimeStamp with the measure's start mark.

The duration attribute must return a DOMHighResTimeStamp with the duration of the measure.

The PerformanceMeasure interface contains the following additional attribute

The detail attribute must return the value it is set to (it's copied from the PerformanceMeasureOptions dictionary).

4. 处理

A user agent implementing the User Timing API would need to include "mark" and "measure" in supportedEntryTypes. This allows developers to detect support for User Timing.

4.1 mark 转换为 timestamp

To convert a mark to a timestamp, given a mark that is a DOMString or DOMHighResTimeStamp run these steps

  1. If mark is a DOMString and it has the same name as a read only attribute in the PerformanceTiming interface, let end time be the value returned by running the convert a name to a timestamp algorithm with name set to the value of mark.
  2. Otherwise, if mark is a DOMString, let end time be the value of the startTime attribute from the most recent occurrence of a PerformanceMark object in the performance entry buffer whose name is mark. If no matching entry is found, throw a SyntaxError.
  3. Otherwise, if mark is a DOMHighResTimeStamp
    1. If mark is negative, throw a TypeError.
    2. Otherwise, let end time be mark.

4.2 name 转换为 timestamp

To convert a name to a timestamp given a name that is a read only attribute in the PerformanceTiming interface, run these steps

  1. If the global object is not a Window object, throw a TypeError.
  2. If name is navigationStart, return 0.
  3. startTimenavigationStartPerformanceTiming 接口中的值。
  4. endTimenamePerformanceTiming 接口中的值。
  5. 如果 endTime0抛出 一个 InvalidAccessError
  6. 返回 endTime 减去 startTime 的结果。

PerformanceTiming 接口在 [NAVIGATION‑TIMING] 中被定义,现已视为过时。仍然支持使用 PerformanceTiming 接口中的名称,以保持向后兼容,但未来并无计划将此功能扩展到在 [NAVIGATION‑TIMING‑2](或其他接口)中定义的 PerformanceNavigationTiming 接口的名称。

6. 隐私与安全

本节是非规范性的。

本规范中定义的接口会暴露页面特定 JavaScript 活动的潜在敏感时间信息。请参阅 [HR‑TIME‑2],了解公开高分辨率时间信息的隐私和安全考虑。

由于 Web 平台的设计假设同一页面上包含的任何脚本与其他脚本拥有相同的访问权限,无论这些脚本的来源如何,因此本规范定义的接口不对记录或检索已记录的时间信息设置任何限制——即页面上任何脚本记录的用户时间标记或度量,都可以被同一页面上的其他脚本读取,且不受来源限制。

A. 致谢

感谢 James Simonsen、Jason Weber、Nic Jansma、Philippe Le Hegaret、Karen Anderson、Steve Souders、Sigbjorn Vik、Todd Reifsteck 与 Tony Gentilcore 对本工作的贡献。

B. 参考资料

B.1 规范性参考资料

[HR‑TIME‑2]
High Resolution Time Level 2。Ilya Grigorik。W3C。2019 年 11 月 21 日。W3C Recommendation。URL:https://w3org.cn/TR/hr-time-2/
[HTML]
HTML 标准. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. 活标准. URL: https://html.whatwg.cn/multipage/
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[NAVIGATION‑TIMING]
Navigation Timing。Zhiheng Wang。W3C。2012 年 12 月 17 日。W3C Recommendation。URL:https://w3org.cn/TR/navigation-timing/
[PERFORMANCE-TIMELINE-2]
Performance Timeline。Nicolas Pena Moreno。W3C。2025 年 5 月 21 日。CRD。URL:https://w3org.cn/TR/performance-timeline/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. 1997年3月. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
RFC 2119 关键词中大小写的歧义. B. Leiba. IETF. 2017年5月. 最佳当前实践. URL: https://www.rfc-editor.org/rfc/rfc8174
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/

B.2 参考性参考资料

[ECMA-262]
ECMAScript 语言规范. Ecma International. URL: https://tc39.es/ecma262/multipage/
[NAVIGATION-TIMING-2]
Navigation Timing Level 2。Yoav Weiss;Noam Rosenthal。W3C。2026 年 2 月 25 日。W3C Working Draft。URL:https://w3org.cn/TR/navigation-timing-2/
[USER-TIMING-2]
User Timing 第2版. Ilya Grigorik. W3C. 2019年2月26日. W3C 推荐稿. URL: https://w3org.cn/TR/user-timing-2/