User Timing

W3C 勧告候補草案

この文書についての詳細
このバージョン:
https://www.w3.org/TR/2026/CRD-user-timing-20260311/
最新公開バージョン:
https://www.w3.org/TR/user-timing/
最新の編集者草案:
https://w3c.github.io/user-timing/
履歴:
https://www.w3.org/standards/history/user-timing
コミット履歴
テストスイート:
https://wpt.fyi/results/user-timing
実装レポート:
https://wpt.fyi/results/user-timing
編集者:
Nicolás Peña Moreno (Google)
以前の編集者:
Ilya Grigorik (Google)
Jatinder Mann (Microsoft Corp.) (2014年2月まで)
Zhiheng Wang (Google Inc.) (2013年7月まで)
Anderson Quach (Microsoft Corp.) (2011年3月まで)
フィードバック:
GitHub w3c/user-timing (プルリクエスト, 新しい issue, 未解決の issue)
public-web-perf@w3.org 宛てに 件名を [UserTiming] として送信してください (アーカイブ)
実装
User Timing は利用できますか?

概要

この仕様は、Web 開発者が高精度のタイムスタンプにアクセスできるようにすることで、アプリケーションのパフォーマンスを測定するのに役立つインターフェイスを定義します。

この文書のステータス

この節は、公開時点におけるこの 文書のステータスを説明するものです。現在の W3C 公開物と、この技術報告書の最新リビジョンの一覧は、 W3C 標準および草案 インデックスで確認できます。

この User Timing 仕様は、[USER-TIMING-2] を置き換えることを意図しており、以下を含みます:

この文書は、Web Performance Working Group により、 Recommendation track を用いた Candidate Recommendation Draft として公開されました。

Candidate Recommendation としての公開は、 W3C およびそのメンバーによる承認を意味するものではありません。Candidate Recommendation Draft は、ワーキンググループが後続の Candidate Recommendation Snapshot に含めることを意図している、 以前の Candidate Recommendation からの変更を統合します。

これは草案文書であり、いつでも他の文書によって更新、置換、または廃止される可能性があります。 作業中の文書以外のものとしてこの文書を引用することは不適切です。

この文書は、 W3C Patent Policy の下で運営されているグループによって作成されました。 W3C は、 そのグループの成果物に関連して行われた 特許開示の公開一覧 を維持しています。そのページには、特許を開示するための 手順も含まれています。ある個人が、 Essential Claim(s) を含むとその個人が考える特許について実際の知識を有している場合、その情報を W3C Patent Policy の第 6 節に従って開示しなければなりません。

この文書は、 2025年8月18日版 W3C Process Document によって管理されます。

1. 简介

本节是非规范性的。

Web 开发者需要能够评估和理解其 应用程序的性能特征。虽然 JavaScript [ECMA-262] 提供了一种测量 应用程序延迟的机制(从 Date.now() 方法取得当前时间戳),但该 时间戳的精度会因用户代理而异。

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

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

async function run() {
  performance.mark("startTask1");
  await doTask1(); // 一些开发者代码
  performance.mark("endTask1");

  performance.mark("startTask2");
  await doTask2(); // 一些开发者代码
  performance.mark("endTask2");

  // 将它们记录出来
  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. User Timing

3.1 Performance 接口的扩展

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() 方法

存储带有关联名称的时间戳(一个“mark”)。它 MUST 运行这些 步骤:

  1. 运行 PerformanceMark 构造器,并令 entry 为新创建的对象。
  2. 排队 entry
  3. entry 添加到 performance entry buffer
  4. 返回 entry
3.1.1.1 PerformanceMarkOptions 字典
detail
要包含在标记中的元数据。
startTime
要用作标记时间的时间戳。

3.1.2 clearMarks() 方法

移除带有关联名称的已存储时间戳。它 MUST 运行这些 步骤:

  1. 如果省略了 markName,则从 PerformanceMark 对象中移除所有位于 performance entry buffer 中的对象。
  2. 否则,移除 PerformanceMark 对象中列在 performance entry buffer 中且其 name markName 的所有对象。
  3. 返回 undefined

3.1.3 measure() 方法

存储两个标记之间的 DOMHighResTimeStamp 持续时间,并附带关联名称(一个“measure”)。它 MUST 运行这些步骤:

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

3.1.4 clearMeasures() 方法

移除带有关联名称的已存储时间戳。它 MUST 运行这些步骤:

  1. 如果省略了 measureName,则移除 PerformanceMeasure 对象中位于 performance entry buffer 中的所有对象。
  2. 否则,移除 PerformanceMeasure 对象中列在 performance entry buffer 中且其 name measureName 的所有对象。
  3. 返回 undefined

3.2 PerformanceMark 接口

PerformanceMark 接口还会将通过 Performance 接口的 mark() 方法创建的标记暴露给 Performance Timeline

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

PerformanceMark 接口扩展了 PerformanceEntry 接口的以下属性:

name 属性必须返回该标记的名称。

entryType 属性必须返回 DOMString "mark"

startTime 属性必须返回一个 DOMHighResTimeStamp, 其值为该标记的时间值。

duration 属性必须返回值为 0DOMHighResTimeStamp

PerformanceMark 接口包含以下 附加属性:

detail 属性必须返回其被设置为的值(它是从 PerformanceMarkOptions 字典复制而来的)。

3.2.1 PerformanceMark 构造器

PerformanceMark 构造器必须运行 以下步骤:

  1. 如果 当前 全局对象是一个 Window 对象,并且 markName 使用了与 PerformanceTiming 接口中的某个只读属性相同的名称, 则抛出一个 SyntaxError
  2. 使用当前 全局对象realm 创建一个新的 PerformanceMark 对象 (entry)。
  3. entryname 属性设置为 markName
  4. entryentryType 属性设置为 DOMString "mark"
  5. 按如下方式设置 entrystartTime 属性:
    1. 如果 markOptionsstartTime 成员 存在,则:
      1. 如果 markOptionsstartTime 为负数,则抛出一个 TypeError
      2. 否则,将 entrystartTime 设置为 markOptionsstartTime 的值。
    2. 否则,将其设置为 Performance 对象的 now() 方法将会返回的值。
  6. entryduration 属性设置为 0
  7. 如果 markOptionsdetail 为 null,则将 entrydetail 设置为 null。
  8. 否则:
    1. record 为对 markOptionsdetail 调用 StructuredSerialize 算法的结果。
    2. entrydetail 设置为 以 record当前 realm 调用 StructuredDeserialize 算法的结果。

3.3 PerformanceMeasure 接口

PerformanceMeasure 接口还会将 通过 Performance 接口的 measure() 方法创建的度量暴露给 Performance Timeline

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

PerformanceMeasure 接口扩展了 PerformanceEntry 接口的以下属性:

name 属性必须返回该度量的名称。

entryType 属性必须返回 DOMString "measure"

startTime 属性必须返回一个 DOMHighResTimeStamp, 其值为该度量的开始标记。

duration 属性必须返回一个 DOMHighResTimeStamp, 其值为该度量的持续时间。

PerformanceMeasure 接口包含 以下附加属性:

detail 属性必须返回其被设置为的值(它是 从 PerformanceMeasureOptions 字典复制而来的)。

4. 处理

实现 User Timing API 的用户代理需要在 supportedEntryTypes 中包含 "mark""measure"。这允许开发者检测对 User Timing 的支持。

4.1 mark 转换为 timestamp

将标记转换为时间戳,给定一个作为 DOMStringDOMHighResTimeStampmark,运行这些步骤:

  1. 如果 mark 是一个 DOMString,并且它与 PerformanceTiming 接口中的某个只读属性同名,则令 end time 为在 name 设置为 mark 的值时运行 convert a name to a timestamp 算法 所返回的值。
  2. 否则,如果 mark 是一个 DOMString,则令 end timeperformance entry buffer 中其 name markPerformanceMark 对象的最近一次出现中的 startTime 属性值。如果未找到匹配项,则抛出一个 SyntaxError
  3. 否则,如果 mark 是一个 DOMHighResTimeStamp
    1. 如果 mark 为负数,则抛出一个 TypeError
    2. 否则,令 end timemark

4.2 name 转换为 timestamp

将名称转换为 时间戳, 给定一个作为 PerformanceTiming 接口中的只读 属性name,运行这些步骤:

  1. 如果全局 对象不是 Window 对象,则抛出一个 TypeError
  2. 如果 namenavigationStart,则返回 0
  3. startTimePerformanceTiming 接口中 navigationStart 的值。
  4. endTimePerformanceTiming 接口中 name 的值。
  5. 如果 endTime0,则抛出一个 InvalidAccessError
  6. 返回从 endTime 中减去 startTime 的结果。

PerformanceTiming 接口定义于 [NAVIGATION-TIMING],并且 现在被视为已废弃。支持使用来自 PerformanceTiming 接口的名称,是为了保持向后兼容,但未来没有计划将此 功能扩展到 [NAVIGATION-TIMING-2] 中定义的 PerformanceNavigationTiming 接口(或其他接口)中的名称。

6. 隐私与安全

本节是非规范性的。

本规范定义的接口会暴露页面中特定 JavaScript 活动的、可能 敏感的计时信息。有关暴露 高分辨率计时信息的隐私和安全注意事项,请参见 [HR-TIME-2]。

由于 Web 平台的设计遵循这样一个不变原则:页面中包含的任何 脚本都与同一页面中包含的任何其他脚本具有相同的访问权限, 无论这些脚本的源如何, 本规范定义的接口不会对 已记录计时信息的记录或检索施加任何限制——也就是说,页面中包含的任何脚本记录的 user timing mark 或 measure,都可以被 同一页面上运行的任何其他脚本读取,而不论其源如何。

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. 21 November 2019. W3C Recommendation. URL: https://www.w3.org/TR/hr-time-2/
[HTML]
HTML Standard. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/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. 17 December 2012. W3C Recommendation. URL: https://www.w3.org/TR/navigation-timing/
[PERFORMANCE-TIMELINE-2]
Performance Timeline. Nicolas Pena Moreno. W3C. 21 May 2025. CRD. URL: https://www.w3.org/TR/performance-timeline/
[RFC2119]
Key words for use in RFCs to Indicate Requirement Levels. S. Bradner. IETF. March 1997. Best Current Practice. URL: https://www.rfc-editor.org/rfc/rfc2119
[RFC8174]
Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words. B. Leiba. IETF. May 2017. Best Current Practice. 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 Language Specification. Ecma International. URL: https://tc39.es/ecma262/multipage/
[NAVIGATION-TIMING-2]
Navigation Timing Level 2. Yoav Weiss; Noam Rosenthal. W3C. 25 February 2026. W3C Working Draft. URL: https://www.w3.org/TR/navigation-timing-2/
[USER-TIMING-2]
User Timing Level 2. Ilya Grigorik. W3C. 26 February 2019. W3C Recommendation. URL: https://www.w3.org/TR/user-timing-2/