Copyright © 2024 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
本规范通过提供存储和检索高分辨率性能度量数据的方法,扩展了高分辨率时间规范 [HR-TIME-3]。
本节描述了本文档在发布时的状态。当前 W3C 出版物的列表以及此技术报告的最新版本可以在 W3C 技术报告索引 中找到,网址为 https://www.w3.org/TR/。
本性能时间线规范取代了 [PERFORMANCE-TIMELINE] 的第一个版本,并包括以下内容:
Performance
接口的基本定义;
PerformanceEntry
[WORKERS];
PerformanceObserver
的支持。
本文档由 Web 性能工作组 作为候选推荐草案使用 推荐流程 发布。
作为候选推荐发布并不意味着得到了 W3C 及其成员的认可。候选推荐草案整合了工作组计划包含在后续候选推荐快照中的前一版候选推荐的变更。
这是一个草案文档,可能随时被更新、替代或废弃。除了作为正在进行的工作外,引用此文档是不合适的。
本文件由根据 W3C 专利政策 运营的工作组制作。 W3C 维护了与该工作组交付物相关的任何专利披露的 公开列表;该页面还包括披露专利的说明。若个人实际了解包含 必要声明 的专利,则必须根据 W3C 专利政策第6节 进行披露。
本文档受 2023年11月3日 W3C 流程文档 管辖。
本节为非规范性内容。
准确测量 Web 应用程序的性能特性是提高 Web 应用程序速度的重要方面。 本规范定义了必要的 性能时间线 基元,使 Web 开发人员能够访问、监测和检索 Web 应用程序整个生命周期中的各种性能指标。
[NAVIGATION-TIMING-2]、[RESOURCE-TIMING-2] 和 [USER-TIMING-2] 是定义与文档导航、页面资源和开发者脚本相关的时间信息的规范示例。 这些和其他性能接口共同定义了描述 Web 应用程序 性能时间线 的性能指标。 例如,以下脚本展示了开发人员如何访问 性能时间线 以获取与文档导航、页面资源和开发人员脚本相关的性能指标:
<!doctype html>
<html>
<head></head>
<body onload="init()">
<img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
<script>
function init() {
// 参见 [[USER-TIMING-2]]
performance.mark("startWork");
doWork(); // 一些开发人员代码
performance.mark("endWork");
measurePerf();
}
function measurePerf() {
performance
.getEntries()
.map(entry => JSON.stringify(entry, null, 2))
.forEach(json => console.log(json));
}
</script>
</body>
</html>
或者,开发人员可以通过 性能时间线 观察新性能指标,或通过 PerformanceObserver
接口获取指定类型的先前缓冲的性能指标。
PerformanceObserver
接口被添加进来,旨在解决第一例中基于缓冲区的方法的局限性。通过使用 PerformanceObserver 接口,应用程序可以:
鼓励开发人员尽可能使用 PerformanceObserver
。此外,新的性能 API 和指标可能只通过 PerformanceObserver
接口提供。观察者通过在构造函数中指定回调和通过
observe()
方法指定感兴趣的性能条目类型来工作。用户代理选择何时执行回调,回调接收已排队的性能条目。
使用 PerformanceObserver
接口时有关于初始页面加载的特殊考虑:注册必须处于活动状态才能接收事件,但注册脚本可能不可用,也可能不希望位于关键路径中。为解决这个问题,用户代理会在页面构建时缓冲一定数量的事件,并可以通过注册观察者时的 buffered
标志访问这些缓冲事件。当设置此标志时,用户代理会检索并调度其已缓冲的指定类型的事件,并在执行 observe()
调用后的第一个回调中传递它们。
缓冲事件的数量由定义指标的规范决定,缓冲旨在用于前 N 个事件;缓冲不是无界或连续的。
<!doctype html>
<html>
<head></head>
<body>
<img id="image0" src="https://www.w3.org/Icons/w3c_main.png" />
<script>
// 知道我们想要使用的条目类型何时不受支持。
function detectSupport(entryTypes) {
for (const entryType of entryTypes) {
if (!PerformanceObserver.supportedEntryTypes.includes(entryType)) {
// 向客户端分析指示 |entryType| 不受支持。
}
}
}
detectSupport(["resource", "mark", "measure"]);
const userTimingObserver = new PerformanceObserver(list => {
list
.getEntries()
// 获取我们感兴趣的值
.map(({ name, entryType, startTime, duration }) => {
const obj = {
"Duration": duration,
"Entry Type": entryType,
"Name": name,
"Start Time": startTime,
};
return JSON.stringify(obj, null, 2);
})
// 将它们显示在控制台。
.forEach(console.log);
// 处理完事件后断开连接。
userTimingObserver.disconnect();
});
// 订阅新事件以用于用户时序。
userTimingObserver.observe({entryTypes: ["mark", "measure"]});
const resourceObserver = new PerformanceObserver(list => {
list
.getEntries()
// 获取我们感兴趣的值
.map(({ name, startTime, fetchStart, responseStart, responseEnd }) => {
const obj = {
"Name": name,
"Start Time": startTime,
"Fetch Start": fetchStart,
"Response Start": responseStart,
"Response End": responseEnd,
};
return JSON.stringify(obj, null, 2);
})
// 将它们显示在控制台。
.forEach(console.log);
// 处理完事件后断开连接。
resourceObserver.disconnect();
});
// 检索缓冲事件并订阅资源时序的较新事件。
resourceObserver.observe({type: "resource", buffered: true});
</script>
</body>
</html>
与标记为非规范性的章节一样,本规范中的所有创作指南、图表、示例和注释都是非规范性的。本规范中的其他内容是规范性的。
本文档中的关键字 必须、禁止 和 应该 应按照 BCP 14 [RFC2119] [RFC8174] 中的描述进行解释,且仅当它们完全大写时,如此处所示。
以算法或特定步骤表述的一致性要求可以以任何方式实现,只要最终结果等效即可。(特别是,本规范中定义的算法旨在易于理解,而非旨在提高性能)。
每个 全局对象 具有以下属性:
DOMString
,表示缓冲区所属的条目类型。该 映射 的 值 是以下元组:
PerformanceEntry
对象的 性能条目缓冲区,初始为空。boolean
类型的 可从时间线上获取,初始化为该条目类型的 注册表 值。每个 文档 具有:
PerformanceEntry
,初始未设置。
为了获取 相关的性能条目元组,输入 entryType 和 globalObject 时,执行以下步骤:
Performance
接口这扩展了来自 [HR-TIME-3] 的 Performance
接口,并提供用于从
性能时间线 中检索性能指标数据的性能相关属性和方法。
WebIDLpartial interface Performance {
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
typedef sequence<PerformanceEntry
> PerformanceEntryList
;
PerformanceEntryList
表示 PerformanceEntry
的序列,为开发人员提供了在 JavaScript
数组上可以找到的所有便捷方法。
返回由 按名称和类型过滤缓冲区映射 算法返回的 PerformanceEntryList
对象,name 和 type 设置为 null
。
返回由 按名称和类型过滤缓冲区映射 算法返回的 PerformanceEntryList
对象,其中
name 设置为 null
,而 type 设置为方法的输入 type
参数。
返回由 按名称和类型过滤缓冲区映射 算法返回的 PerformanceEntryList
对象,其中
name 设置为方法的输入 name
参数,type 如果省略了可选的
entryType
,则设置为 null
,否则设置为方法的输入 type
参数。
PerformanceEntry
接口包含各种性能指标的数据。
WebIDL[Exposed=(Window,Worker)]
interface PerformanceEntry
{
readonly attribute unsigned long long id
;
readonly attribute DOMString name
;
readonly attribute DOMString entryType
;
readonly attribute DOMHighResTimeStamp startTime
;
readonly attribute DOMHighResTimeStamp duration
;
[Default] object toJSON
();
};
name
PerformanceEntry
对象的标识符。该标识符不必唯一。
entryType
所有 entryType
值都在相关的注册表中定义。示例包括:"mark"
和 "measure"
[USER-TIMING-2],"navigation"
[NAVIGATION-TIMING-2],
以及 "resource"
[RESOURCE-TIMING-2]。
startTime
duration
duration
属性的 getter 步骤是:
如果this 的
结束时间
为 0,则返回 0;否则,返回 this 的
结束时间
减去 this 的
startTime
。
navigationId
当调用 toJSON
时,执行 [WebIDL] 的 默认 toJSON 步骤。
PerformanceEntry
有一个 DOMHighResTimeStamp
的
结束时间,初始值为 0。
为了 初始化一个 PerformanceEntry
entry,给定一个 DOMHighResTimeStamp
的
startTime,一个 DOMString
的 entryType,一个 DOMString
的名称,和一个可选的
DOMHighResTimeStamp
的
endTime(默认值为 0
):
PerformanceObserver
接口可以用于
观察 性能时间线,以便在记录新的性能指标时收到通知,并且可以选择缓冲的性能指标。
每个 PerformanceObserver
关联以下概念:
PerformanceObserverCallback
观察者回调。
PerformanceEntryList
的对象,
被称为 观察者缓冲区,最初是空的。
"undefined"
的 DOMString
类型的 观察者类型。
PerformanceObserver(callback)
构造函数必须创建一个新的
PerformanceObserver
对象,
其 观察者回调 被设置为 callback,然后返回它。
注册的性能观察者是一个由观察者成员(PerformanceObserver
对象)和选项列表成员
(一个由 PerformanceObserverInit
字典组成的列表)组成的结构体。
WebIDLcallback PerformanceObserverCallback
= undefined (PerformanceObserverEntryList
entries,
PerformanceObserver
observer,
optional PerformanceObserverCallbackOptions
options = {});
[Exposed=(Window,Worker)]
interface PerformanceObserver
{
constructor
(PerformanceObserverCallback
callback);
undefined observe
(optional PerformanceObserverInit
options = {});
undefined disconnect
();
PerformanceEntryList
takeRecords
();
[SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes
;
};
为了将性能开销降到最低,应用程序应仅订阅感兴趣的事件类型,并在不再需要观察性能数据时断开观察者。 不支持按名称过滤,因为这将隐式地要求订阅所有事件类型——这是可能的,但不鼓励这样做,因为这会生成大量事件。
WebIDLdictionary PerformanceObserverCallbackOptions
{
unsigned long long droppedEntriesCount
;
};
droppedEntriesCount
PerformanceObserver
的 需要丢弃条目 设置时,
观察者正在观察的条目类型的丢弃条目数。observe()
方法指示用户代理注册
观察者并必须执行以下步骤:
entryTypes
和 type
成员
都被省略,则 抛出一个 "TypeError
"。
entryTypes
存在
且
任何其他
成员也存在,则 抛出一个 "TypeError
"。
"undefined"
:
"single"
且 options 的 entryTypes
成员存在,则 抛出一个
"InvalidModificationError
"。
"multiple"
且 options 的 type
成员
存在,则 抛出一个
"InvalidModificationError
"。
"multiple"
,请运行以下步骤:
entryTypes
序列。
"single"
。
type
不包含
在
relevantGlobal 的 受支持条目类型的冻结数组
中,则中止这些步骤。用户代理 应该 通知
开发者当这种情况发生时,例如通过控制台警告。
buffered
标志
被设置:
一个 PerformanceObserver
对象需要
始终调用
observe()
使用
options 的 entryTypes
设置 或
始终
调用
observe()
使用
options 的 type
设置。
如果一个 PerformanceObserver
调用 observe()
使用 entryTypes
并且还
调用了
observe 与
type
,则会抛出异常。
这是为了避免混淆调用的堆叠方式。当
使用 entryTypes
时,不能使用 PerformanceObserverInit
中的其他参数。
此外,
多次 observe()
调用将被
覆盖
为了向后兼容
并且因为在这种情况下一个调用应该足够。另一方面,
使用 type
时,调用
将堆叠,因为单个调用只能指定一种类型。调用
observe()
使用重复的 type
也将被覆盖。
WebIDLdictionary PerformanceObserverInit
{
sequence<DOMString> entryTypes
;
DOMString type
;
boolean buffered
;
};
entryTypes
type
buffered
WebIDL[Exposed=(Window,Worker)]
interface PerformanceObserverEntryList
{
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
每个 PerformanceObserverEntryList
对象都有一个相关的
条目列表,
其中包含一个 PerformanceEntryList
,并在构造时初始化。
返回一个 PerformanceEntryList
对象,
该对象是通过 按名称和类型过滤缓冲区 算法
获取的,其中 this 的 条目列表 中的
name 和 type 均设置为 null
。
返回一个 PerformanceEntryList
对象,
通过 按名称和类型过滤缓冲区 算法返回,
this 的 条目列表 中,
name 设置为 null
,并且 type 设置为方法输入的 type
参数。
返回一个 PerformanceEntryList
对象,
通过 按名称和类型过滤缓冲区 算法返回,
this 的 条目列表 中,
name 设置为方法输入的 name
参数,
如果省略了可选的 entryType
,则 type 设置为 null
,
否则设置为方法输入的 type
参数。
takeRecords()
方法必须
返回 此对象的
观察者缓冲区的副本,并清空
此对象的 观察者缓冲区。
disconnect()
方法必须执行以下操作:
supportedEntryTypes
属性每个 全局对象 都有一个相关的 支持的条目类型的冻结数组, 该数组根据支持的条目类型,从 注册表 中按字母顺序排序后 通过 FrozenArray 创建。
当调用 supportedEntryTypes
属性的 getter 时,运行以下步骤:
此属性允许 Web 开发者轻松了解用户代理支持的条目类型。
要排队一个 PerformanceEntry (newEntry),请执行以下步骤:
id
未设置:
PerformanceObserver
对象。
entryType
值。
navigationId
设置为
relevantGlobal 的 相关文档
的 最近的导航的 id
。
navigationId
设置为 null。如果 regObs 的 选项列表 包含一个
PerformanceObserverInit
的 options,其 entryTypes
成员包括
entryType,或者其 type
成员
等于
entryType:
在给定relevantGlobal作为输入的情况下,要求排队PerformanceObserver任务时,请执行以下步骤:
PerformanceObserverEntryList
,其条目列表设置为entries。
PerformanceObserverInit
item:
PerformanceObserverCallbackOptions
,其droppedEntriesCount
已设置为droppedEntriesCount(如果droppedEntriesCount不为空),否则未设置。
性能时间线的任务队列是一个低优先级队列,如果可能,用户代理应在空闲时段处理此队列,以尽量减少性能监控代码的影响。
当要求使用可选的name和type运行按名称和类型过滤缓冲区映射算法时,请执行以下步骤:
startTime
。
当要求使用buffer、name和type作为输入运行按名称和类型过滤缓冲区算法时,请执行以下步骤:
要判断性能条目缓冲区是否已满,输入tuple,请执行以下步骤:
当被要求为entry生成生成一个id时,执行以下步骤:
用户代理可以选择每次增加一个小的随机整数作为last performance entry id。用户代理不得选择一个全局的随机整数,并将其应用于所有全局对象的last performance entry id,因为这可能会引入跨域泄漏。
初始的last performance entry id值是随机的,用户代理会选择一个小数增加,而不是1,以防止开发者将其视为在Web应用程序中生成的条目数量的计数器。
本规范扩展了由[HR-TIME-3]定义的Performance
接口,并提供了从性能时间线中排队和检索条目的方法。有关暴露高分辨率时间信息的隐私注意事项,请参阅[HR-TIME-3]。每个引入新性能条目的新规范也应有其自己的隐私注意事项。
最后的性能条目ID故意初始化为随机值,并在每次新的PerformanceEntry
被排队时通过另一个小值递增。用户代理可以选择对所有用户使用一致的递增值,也可以为每个全局对象选择不同的递增值,或者每次选择一个新的随机递增值。然而,为防止跨源泄露并确保不会因此启用指纹识别,用户代理不得仅仅选择一个唯一的随机整数,并将其作为所有PerformanceEntry
对象在所有全局对象中的一致递增值。
本规范扩展了由[HR-TIME-3]定义的Performance
接口,并提供了从性能时间线中排队和检索条目的方法。有关暴露高分辨率时间信息的安全注意事项,请参阅[HR-TIME-3]。每个引入新性能条目的新规范也应有其自己的安全注意事项。
WebIDLpartial interface Performance {
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
typedef sequence<PerformanceEntry
> PerformanceEntryList
;
[Exposed=(Window,Worker)]
interface PerformanceEntry
{
readonly attribute unsigned long long id
;
readonly attribute DOMString name
;
readonly attribute DOMString entryType
;
readonly attribute DOMHighResTimeStamp startTime
;
readonly attribute DOMHighResTimeStamp duration
;
readonly attribute unsigned long long navigationId
;
[Default] object toJSON
();
};
callback PerformanceObserverCallback
= undefined (PerformanceObserverEntryList
entries,
PerformanceObserver
observer,
optional PerformanceObserverCallbackOptions
options = {});
[Exposed=(Window,Worker)]
interface PerformanceObserver
{
constructor
(PerformanceObserverCallback
callback);
undefined observe
(optional PerformanceObserverInit
options = {});
undefined disconnect
();
PerformanceEntryList
takeRecords
();
[SameObject] static readonly attribute FrozenArray<DOMString> supportedEntryTypes
;
};
dictionary PerformanceObserverCallbackOptions
{
unsigned long long droppedEntriesCount
;
};
dictionary PerformanceObserverInit
{
sequence<DOMString> entryTypes
;
DOMString type
;
boolean buffered
;
};
[Exposed=(Window,Worker)]
interface PerformanceObserverEntryList
{
PerformanceEntryList
getEntries
();
PerformanceEntryList
getEntriesByType
(DOMString type);
PerformanceEntryList
getEntriesByName
(DOMString name, optional DOMString type);
};
感谢 Arvind Jain, Boris Zbarsky, Jatinder Mann, Nat Duca, Philippe Le Hegaret, Ryosuke Niwa, Shubhie Panicker, Todd Reifsteck, Yoav Weiss 和 Zhiheng Wang 对本工作的贡献。
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: