版权所有 © 2026 万维网联盟 (W3C)。W3C® 法律免责声明、商标及宽松文档许可规则适用。
本规范定义了一个接口,帮助 Web 开发者通过提供高精度时间戳来测量其应用的性能。
本节描述了本文件发布时的状态。当前的 W3C 出版物列表和本技术报告的最新版本可以在 W3C 标准和草案索引中找到。
此用户计时规范旨在取代 [USER-TIMING-2] 并包括
此文档由 Web 性能工作组 作为候选推荐草案发布,使用 推荐轨道。
作为候选推荐标准发布并不意味着得到 W3C 及其成员的认可。候选推荐标准草案整合了来自先前候选推荐标准的更改,工作组打算将其包含在后续的候选推荐标准快照中。
这是一份草案文件,可能随时被其他文件更新、替换或废弃。将其作为进展中的工作以外的引用是不恰当的。
此文档由在 W3C 专利政策 下运作的工作组制作。W3C 维护一份 公开的专利披露列表,该页面同样包含披露专利的说明。任何实际了解认为包含 关键声明 的专利的个人,必须依据 W3C 专利政策第 6 节进行披露。
本文件受 2025 年 8 月 18 日 W3C 流程文档约束。
本节是非规范性的。
Web 开发者需要能够评估并理解其应用的性能特征。虽然 JavaScript [ECMA-262] 提供了一种通过 Date.now() 方法获取当前时间戳来测量应用延迟的机制,但此时间戳的精度在不同用户代理间有所差异。
本文档定义了 PerformanceMark 与 PerformanceMeasure 接口,以及对 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,
});
});
});
除了标记为非规范性的章节外,本规范中的所有创作指南、图表、示例和注释均为非规范性内容。本规范中的其他所有内容均为规范性内容。
本文件中的关键词 MAY 与 MUST 依据 BCP 14 [RFC2119] [RFC8174] 的解释进行解读,且仅在全部大写出现时才适用,如本文所示。
某些合规性要求以属性、方法或对象的形式表述。这类要求应解释为对用户代理的要求。
本规范中的 IDL 片段 MUST 被解释为符合 Web IDL 规范的必需 IDL 片段。[WEBIDL]
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);
};
存储带有关联名称(即 “标记”)的时间戳。它 MUST 运行以下步骤
detailstartTime移除带有关联名称的已存时间戳。它 MUST 运行以下步骤
PerformanceMark 对象。name 等于 markName 的所有 PerformanceMark 对象。存储两次标记之间的 DOMHighResTimeStamp 持续时间以及关联的名称(即 “度量”)。它 MUST 运行以下步骤
PerformanceMeasureOptions 对象且 start、end、duration、detail 中至少有一个 存在,则运行以下检查
PerformanceMeasureOptions 对象且其 end 成员 存在,则令 end time 为运行 将标记转换为时间戳 算法并传入 startOrMeasureOptions 的 end 所得到的值。PerformanceMeasureOptions 对象且其 start 与 duration 成员均 存在
Performance 对象的 now() 方法返回的值。PerformanceMeasureOptions 对象且其 start 成员 存在,则令 start time 为运行 将标记转换为时间戳 算法并传入 startOrMeasureOptions 的 start 所得到的值。PerformanceMeasureOptions 对象且其 duration 与 end 成员均 存在
DOMString,则令 start time 为运行 将标记转换为时间戳 算法并传入 startOrMeasureOptions 所得到的值。0。PerformanceMeasure 对象(entry),并使用 this 的 相关 realm。name 属性设为 measureName。entryType 属性设为 DOMString "measure"。startTime 属性设为 start time。duration 属性设为从 start time 到 end time 的持续时间。得到的持续时间值 MAY 为负数。detail 属性PerformanceMeasureOptions 对象且其 detail 成员 存在detail 调用 StructuredSerialize 算法的结果。detail 设置为对 record 与当前 realm 调用 StructuredDeserialize 算法的返回值。null。detailstartdurationend移除带有关联名称的已存时间戳。它 MUST 运行以下步骤
PerformanceMeasure 对象。name 等于 measureName 的所有 PerformanceMeasure 对象。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).
PerformanceMark ConstructorThe PerformanceMark constructor must run the following steps
Window object and markName uses the same name as a read only attribute in the PerformanceTiming interface, throw a SyntaxError.PerformanceMark object (entry) with the current global object's realm.name attribute to markName.entryType attribute to DOMString "mark".startTime attribute as follows
duration attribute to 0.detail is null, set entry's detail to null.detail.detail to the result of calling the StructuredDeserialize algorithm on record and the current realm.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).
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.
To convert a mark to a timestamp, given a mark that is a DOMString or DOMHighResTimeStamp run these steps
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.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.DOMHighResTimeStampTypeError.To convert a name to a timestamp given a name that is a read only attribute in the PerformanceTiming interface, run these steps
Window object, throw a TypeError.navigationStart, return 0.navigationStart 在 PerformanceTiming 接口中的值。PerformanceTiming 接口中的值。0,抛出 一个 InvalidAccessError。PerformanceTiming 接口在 [NAVIGATION‑TIMING] 中被定义,现已视为过时。仍然支持使用 PerformanceTiming 接口中的名称,以保持向后兼容,但未来并无计划将此功能扩展到在 [NAVIGATION‑TIMING‑2](或其他接口)中定义的 PerformanceNavigationTiming 接口的名称。
鼓励开发者使用以下推荐的标记名称来标记常见时间点。用户代理 不会验证这些名称的使用是否恰当或与其描述保持一致。
添加这些推荐的标记名称可以帮助性能工具为站点提供更有针对性的指导。这些标记名称还能帮助真实用户监控提供者和用户代理在大规模下收集网页开发者关于其应用性能的信号,并在无需任何站点特定工作情况下把这些信息展示给开发者。
在本示例中,页面在加载后会异步初始化聊天小部件、搜索框和资讯推送。当全部完成后,"mark_fully_loaded" 标记名称使实验室工具和分析提供者能够自动显示该时间。
window.addEventListener("load", (event) => {
Promise.all([
loadChatWidget(),
initializeSearchAutocomplete(),
initializeNewsfeed()]).then(() => {
performance.mark('mark_fully_loaded');
});
});
detail 元数据可以包含关于该特性的任何有用信息,包括在本示例中,FancyJavaScriptFramework 的 ImageOptimizationComponent 被用于对图像进行尺寸优化,以提升性能。代码记录了该特性的使用,从而实验室工具和分析能够测量其是否帮助提升了性能。
performance.mark('mark_feature_usage', {
'detail': {
'feature': 'ImageOptimizationComponent',
'framework': 'FancyJavaScriptFramework'
}
})
本节是非规范性的。
本规范中定义的接口会暴露页面特定 JavaScript 活动的潜在敏感时间信息。请参阅 [HR‑TIME‑2],了解公开高分辨率时间信息的隐私和安全考虑。
由于 Web 平台的设计假设同一页面上包含的任何脚本与其他脚本拥有相同的访问权限,无论这些脚本的来源如何,因此本规范定义的接口不对记录或检索已记录的时间信息设置任何限制——即页面上任何脚本记录的用户时间标记或度量,都可以被同一页面上的其他脚本读取,且不受来源限制。
感谢 James Simonsen、Jason Weber、Nic Jansma、Philippe Le Hegaret、Karen Anderson、Steve Souders、Sigbjorn Vik、Todd Reifsteck 与 Tony Gentilcore 对本工作的贡献。
引用自
引用自
引用自