事件时序 API

W3C 工作草案

关于本文档的更多信息
当前版本:
https://www.w3.org/TR/2025/WD-event-timing-20250526/
最新发布版本:
https://www.w3.org/TR/event-timing/
编辑草案:
https://w3c.github.io/event-timing/
历史版本:
历史记录:
https://www.w3.org/standards/history/event-timing/
测试套件:
https://github.com/web-platform-tests/wpt/tree/master/event-timing
反馈:
GitHub
编辑:
(Google)
前编辑:
(Google)
(Google)

摘要

本文档定义了一个API,为网页作者提供有关因用户交互触发的某些事件的延迟洞察。

本文档状态

本节描述了本文档在发布时的状态。 当前的W3C出版物列表 以及本技术报告的最新修订版 可在W3C标准与草案索引 https://www.w3.org/TR/中查询。

本文档由Web 性能工作组按照推荐轨道工作草案发布。 作为工作草案发布并不意味着得到W3C及其成员的认可。

本文档为草稿文档, 可能会随时更新、替换或废止, 不应将其作为除“正在进行的工作”以外的内容引用。

关于本规范的讨论,建议优先使用GitHub Issues

本文档受2023年11月3日W3C流程文件管理。

本文档由一个依照W3C专利政策运作的团体产生。 W3C维护着与本组交付物相关的专利公开列表; 该页面也包括专利披露的说明。 个人如果确知某项专利且认为其中包含必要声明,必须依照W3C专利政策第6节披露相关信息。

1. 简介

1.1. 概述

本节为非规范性内容。

当用户与网站交互时,他们希望自己的操作能够快速引发网站的变化。 实际上,研究 表明,任何未在100毫秒内处理的用户输入都会被认为是慢的。 因此,及时展示未达到这一标准的输入事件的性能时序信息非常重要。

监测事件延迟的常见方法是注册一个事件监听器。 可以通过事件的 timeStamp 获取事件被创建的时间戳。 此外,还可以在事件处理逻辑开始和结束时调用 performance.now()。 将硬件时间戳与事件处理开始时获得的时间戳相减,开发者可以计算输入延迟:即输入开始被处理所需的时间。 将事件处理开始和结束时的时间戳相减,可以计算事件处理器内执行的同步工作量。 最后,对于同步处理的输入,事件的硬件时间戳到处理事件后的下一次绘制之间的持续时间是一个有用的用户体验指标。

这种方法存在几个根本性缺陷。 首先,要求事件监听器会导致在页面加载初期无法测量事件延迟,因为那时监听器可能还未注册。 其次,只对输入延迟感兴趣的开发者可能被迫为原本没有监听器的事件新增监听器。 这会为事件延迟计算带来不必要的性能开销。 最后,通过这种方法很难测量事件引起的异步工作。

本规范为事件延迟监测提供了另一种解决方案,解决了上述部分问题。 由于时间戳由用户代理计算,测量性能不再需要事件监听器。 这意味着,即使是页面加载早期发生的事件也能被捕获。 同时,这种方式能让分析服务商无需尝试订阅所有可能的事件,也能观察到慢事件。 此外,网站性能不会因不必要的事件监听器而受到影响。 最后,本规范允许开发者获取事件处理后紧接着发生的渲染时序的详细信息, 这有助于衡量事件触发的网站修改所带来的性能开销。

1.2. 交互

本节为非规范性内容。

单次用户交互 (有时称为手势)通常由多个物理硬件输入事件组成。 每个物理输入事件可能会导致用户代理分发多个UIEvent, 每个事件又可能触发多个自定义事件监听器,或触发不同的默认操作。

例如,用户在触屏设备上的一次“点击”交互实际上由一系列物理输入事件构成:

这些物理输入事件可能会分发一系列UIEvent

这些单独的UIEvent 都将成为各自PerformanceEventTiming 条目报告的候选对象,这对于详细时序分析很有价值。

注意:pointermovetouchmove 当前未纳入事件时序考虑

不过,本规范还定义了一种机制,可通过interactionId 将相关的PerformanceEventTiming 分组为交互。 这一机制可以用于定义页面响应指标,称为Interaction to Next Paint (INP)

1.3. 首次输入

本节为非规范性内容。

用户的第一个交互 通常对用户体验影响极大,也往往表现出较慢的响应。

为此,事件时序API会暴露 首次输入 的时序信息, 即 Window 的第一个 PerformanceEventTiming 条目,且 interactionId 不为0。

与大多数 PerformanceEventTiming 不同, 首次输入条目即使未超过指定的 durationThreshold 也会被报告,并且即使未超过默认104毫秒的阈值也会被缓冲。 这一机制可用于定义页面响应性指标,称为首次输入延迟(FID)

这也使开发者能够更好地衡量百分位数和性能提升,即使是那些始终响应非常快的页面,也能纳入数据,无需注册事件处理器。

1.4. 暴露的事件

事件时序 API 只为特定事件暴露时序信息。

给定一个 event,要确定其是否应当纳入事件时序考虑,请执行以下步骤:
  1. 如果 eventisTrusted 属性值为 false,则返回 false。

  2. 如果 eventtype 是以下之一:auxclickclickcontextmenudblclickmousedownmouseentermouseleavemouseoutmouseovermouseuppointeroverpointerenterpointerdownpointeruppointercancelpointeroutpointerleavegotpointercapturelostpointercapturetouchstarttouchendtouchcancelkeydownkeypresskeyupbeforeinputinputcompositionstartcompositionupdatecompositionenddragstartdragenddragenterdragleavedragoverdrop, 返回 true。

  3. 返回 false。

注意:mousemovepointermovepointerrawupdatetouchmovewheel、 以及 drag 被排除在外,因为这些属于“连续”事件。 当前API没有足够的指导来统计和聚合这些事件,从而基于条目获得有意义的性能指标。 因此,这些事件类型不被暴露。

1.5. 事件的测量时机

本节为非规范性内容。 它以较高层次说明了§ 3 处理模型部分所暴露的信息。

事件时序信息只在特定事件发生时被暴露,并且仅当用户输入与后续绘制操作之间的时间差超过某个持续时间阈值时才会暴露。

事件时序 API 会暴露一个 duration 值,表示物理用户输入发生的时间 (通过 EventtimeStamp 估算) 到其 Event相关全局对象关联文档被更新的下一次渲染之间的时间。 此值以 8 毫秒粒度提供。

默认情况下,事件时序 API 会在 duration 大于等于 104 毫秒时进行缓冲和暴露, 但开发者可以通过 PerformanceObserver 设置不同的阈值来观察未来条目。 注意,这不会改变已缓冲的条目,因此 buffered 标志仅用于接收持续时间大于等于默认阈值的历史条目。

一个 Event延迟是浏览器即将运行事件处理器的时间与 EventtimeStamp 之间的差值。 前者作为 PerformanceEventTimingprocessingStart 暴露, 后者作为 PerformanceEventTimingstartTime 暴露。 因此,事件的延迟可按如下方式计算:processingStart - startTime

需注意,事件时序 API 会为事件创建条目,无论是否有事件监听器。 特别是,第一个点击或第一个按键可能并不是用户实际打算与页面功能交互; 许多用户在阅读时会选择文本,或点击空白区域以控制焦点。 这是为了捕获页面监听器注册过晚的问题,也为了捕获那些虽然没有监听器但仍有意义的输入(如悬停效果)的性能。 开发者可以通过忽略那些 processingEnd - processingStart 基本为零的条目来忽略这些情况, 因为 processingEnd事件分发算法结束的时间。

1.6. 使用示例

const observer = new PerformanceObserver(function(list, obs) {
    for (let entry of list.getEntries()) {
        // 输入延迟
        const inputDelay = entry.processingStart - entry.startTime;
        // 处理时长
        const processingDuration = entry.processingEnd - entry.processingStart;
        // 呈现延迟(近似)
        const presentationDelay = Math.max(0, entry.startTime + entry.duration - entry.processingEnd);

        // 获取一些关于此事件目标的信息,如id。
        const targetId = entry.target ? entry.target.id : 'unknown-target';

        console.log(entry.entryType, entry.name, entry.duration, { inputDelay, processingDuration, presentationDelay });
    }
});
observer.observe({ type: 'first-input', buffered: true });
observer.observe({ type: 'event', buffered: true, durationThreshold: 40 });

如下示例计算一个字典,将interactionId 映射到其事件的最大持续时间。 该字典随后可聚合并上报给分析系统。

let maxDurations = {};
new PerformanceObserver(list => {
    for (let entry of list.getEntries()) {
        if (entry.interactionId > 0) {
            let id = entry.interactionId;
            if (!maxDurations[id]) {
                maxDurations[id] = entry.duration;
            } else {
                maxDurations[id] = Math.max(maxDurations[id], entry.duration);
            }
        }
    }
}).observe({ type: 'event', buffered: true, durationThreshold: 16 });

下列为使用此API可实现的示例场景:

2. 事件时序

事件时序增加了如下接口:

2.1. PerformanceEventTiming 接口

[Exposed=Window]
interface PerformanceEventTiming : PerformanceEntry {
    readonly attribute DOMHighResTimeStamp processingStart;
    readonly attribute DOMHighResTimeStamp processingEnd;
    readonly attribute boolean cancelable;
    readonly attribute Node? target;
    readonly attribute unsigned long long interactionId;
    [Default] object toJSON();
};

PerformanceEventTiming 对象报告一个关联的Event的时序信息。

每个PerformanceEventTiming 对象都具有关联概念,初始值均设为null

target 属性的getter需执行以下步骤:

  1. 如果 thiseventTarget 不满足 为绘制时序暴露(参数为null),则返回null。

  2. 返回 thiseventTarget

注意: 实现事件时序API的用户代理需在supportedEntryTypes中包含"first-input"和"event", 适用于Window环境。 这样开发者可以检测事件时序的支持情况。

本节其余内容为非规范性说明。 PerformanceEventTiming 的属性值在§ 3 处理模型中设定, 此处为各属性设定方式的概要说明。

PerformanceEventTiming 扩展了如下PerformanceEntry 接口属性:

name
name 属性的getter返回关联事件type
entryType
entryType 属性的getter返回"event"(用于长事件)或"first-input"(用于第一次用户交互)。
startTime
startTime 属性的getter返回关联事件timeStamp
duration
duration 属性的getter返回 更新渲染步骤在关联事件Document 被分发后完成的时间,与startTime的差值,结果四舍五入到最近的8ms。

PerformanceEventTiming 还具备以下附加属性:

processingStart
processingStart 属性的getter返回在事件分发算法开始时捕获的时间戳。即事件处理器即将执行时。
processingEnd
processingEnd 属性的getter返回在事件分发算法结束时捕获的时间戳。即事件处理器执行完毕时。若无处理器,则等于processingStart
cancelable
cancelable 属性的getter返回关联事件cancelable属性值。
target
target 属性的getter返回关联事件的最后一个target,且该Node 未断开连接且不在shadow DOM中。
interactionId
interactionId 属性的getter返回唯一标识触发关联事件的用户交互的编号。 当关联事件type 不属于以下情况时,该属性为0:

2.2. EventCounts 接口

[Exposed=Window]
interface EventCounts {
    readonly maplike<DOMString, unsigned long long>;
};

EventCounts 对象是一个映射,其中键为事件类型,值为已分发该type的事件数量。 仅当事件的typePerformanceEventTiming 条目支持(见§ 1.4 暴露的事件)时,才会被此映射统计。

2.3. Performance 接口的扩展

[Exposed=Window]
partial interface Performance {
    [SameObject] readonly attribute EventCounts eventCounts;
    readonly attribute unsigned long long interactionCount;
};

eventCounts 属性的 getter 返回this相关全局对象eventCounts

interactionCount 属性的 getter 返回this相关全局对象interactionCount

3. 处理模型

3.1. 对 DOM 规范的修改

一旦 [DOM] 被修改,本节将被移除。

我们对 事件分发算法做如下修改。

在第1步之后,添加以下步骤:

  1. interactionId计算 interactionId(传入 event)的结果。

  2. timingEntry初始化事件时序(传入 event当前高精度时间interactionId)的结果。

在该算法返回步骤之前,添加如下步骤:

  1. 完成事件时序,传入 timingEntryeventtarget 以及 当前高精度时间 作为输入。

注意: 如果某个用户代理跳过了 事件分发算法,它仍然可以选择为该 Event 包含一个条目。 在这种情况下,它会估算 processingStart 的值,并将 processingEnd 设置为同一值。

3.2. 对 HTML 规范的修改

一旦 [HTML] 被修改,本节将被移除。

每个 Window 具有以下相关概念:

更新渲染步骤(位于 事件循环处理模型中),在调用 标记绘制时序的步骤之后,添加如下步骤:
  1. 对于 docs 中每个完全激活Document, 调用算法 分发待处理事件时序条目,传入该 Document

3.3. 对 Performance Timeline 规范的修改

一旦 [PERFORMANCE-TIMELINE-2] 被修改,本节将被移除。

PerformanceObserverInit 字典进行了增强:

partial dictionary PerformanceObserverInit {
    DOMHighResTimeStamp durationThreshold;
};

3.4. 应添加 PerformanceEventTiming

注意: 下述算法用于 [PERFORMANCE-TIMELINE-2] 规范中,以决定何时将 PerformanceEventTiming 条目加入 PerformanceObserver 的缓冲区或性能时序,如 注册表所述。

给定一个 PerformanceEventTiming entry 和一个 PerformanceObserverInit options,判断是否应添加 PerformanceEventTiming,传入 entry 和可选 options,按以下步骤执行:
  1. 如果 entryentryType 属性值等于 "first-input",返回 true。

  2. 断言 entryentryType 属性值等于 "event"。

  3. minDuration 计算如下:

    1. options 不存在,或 optionsdurationThreshold 不存在,则 minDuration 设为 104。

    2. 否则,minDuration 取 16 与 optionsdurationThreshold 值之间的最大值。

  4. entryduration 属性值大于等于 minDuration,返回 true。

  5. 否则,返回 false。

3.5. 增加交互计数

当请求增加交互计数,传入 Window window 对象时,执行以下步骤:
  1. window用户交互值 增加一个由用户代理选择的小数。

  2. interactionCountwindowinteractionCount

  3. interactionCount 设为 interactionCount + 1。

注意:用户交互值每次增加一个由用户代理选择的小数,而不是1,是为了防止开发者将其视为网页应用中发生的用户交互次数计数器。 这样,用户代理可以选择在pointerdown时主动分配一个用户交互值,然后在(如pointercancel)后丢弃,而不是延迟计算该值。

用户代理可以选择每次增加一个小的随机整数,或者选择一个常数。 用户代理不得为所有 Windows 使用共享的全局 用户交互值,因为这可能导致跨域泄露。

3.6. 计算 interactionId

当请求计算 interactionId,传入 event 作为输入时,执行以下步骤:
  1. 如果 eventisTrusted 属性值为 false,则返回 0。

  2. typeeventtype 属性值。

  3. type 不为以下之一:keyupcompositionstartinputpointercancelpointerupclick、 或 contextmenu, 返回 0。

    注意:keydownpointerdown 会在 完成事件时序时标记为待处理,然后在后续事件(如 keyuppointerup)计算 interactionId 时更新。

  4. windowevent相关全局对象

  5. pendingKeyDownswindow待处理 keydown

  6. pointerMapwindow指针交互值映射

  7. pendingPointerDownswindow待处理 pointerdown

  8. typekeyup

    1. eventisComposing 属性值为 true,则返回 0。

    2. codeeventkeyCode 属性值。

    3. pendingKeyDowns[code] 不存在,则返回 0。

    4. entrypendingKeyDowns[code]。

    5. 增加交互计数window

    6. interactionIdwindow用户交互值

    7. entryinteractionId 设为 interactionId

    8. entry 添加到 window待入队条目

    9. 移除 pendingKeyDowns[code]。

    10. 返回 interactionId

  9. typecompositionstart

    1. 对于 pendingKeyDowns所有值中的每个 entry

      1. entry 添加到 window待入队条目

    2. 清空 pendingKeyDowns

    3. 返回 0。

  10. typeinput

    1. event 不是 InputEvent 的实例,则返回 0。 注意:此检查用于排除 Eventtypeinput,但不是文本内容修改的情况。

    2. eventisComposing 属性值为 false,则返回 0。

    3. 增加交互计数window

    4. 返回 window用户交互值

  11. 否则(typepointercancelpointerupclick、 或 contextmenu):

    1. pointerIdeventpointerId 属性值。

    2. typeclick

      1. pointerMap[pointerId] 不存在,则返回 0。

      2. valuepointerMap[pointerId]。

      3. 移除 pointerMap[pointerId]。

      4. 返回 value

    3. 断言 typepointeruppointercancel、 或 contextmenu

    4. pendingPointerDowns[pointerId] 不存在:

      1. typecontextmenu, 返回 window用户交互值

      2. typepointerupwindow已触发 contextmenu 标志为 true:

        1. window已触发 contextmenu 标志设为 false。

        2. 返回 window用户交互值

      3. 否则,返回 0。

    5. pointerDownEntrypendingPointerDowns[pointerId]。

    6. 断言 pointerDownEntryPerformanceEventTiming 条目。

    7. typepointerupcontextmenu

      1. 增加交互计数window

      2. pointerMap[pointerId] 设为 window用户交互值

      3. pointerDownEntryinteractionId 设为 pointerMap[pointerId]。

    8. pointerDownEntry 添加到 window待入队条目

    9. 移除 pendingPointerDowns[pointerId]。

    10. typecontextmenu, 将 window已触发 contextmenu 设为 true。

    11. typepointercancel, 返回 0。

    12. 返回 pointerMap[pointerId]。

注意: 该算法尝试将事件分配到对应的 interactionId。 对于键盘事件,keydown 触发新交互 ID,keyup 需与之前的 keydown 匹配。 对于指针事件,获取 pointerdown 后需等待 pointercancelpointerup 才能确定其 interactionId。 我们尝试让 click 匹配之前 pointerdown 的交互 ID。 如果出现 pointercancelpointerup, 就可以为存储的 pointerdown 条目设置 interactionId。 如果是 pointercancel, 表示不需要为 pointerdown 分配新交互 ID。 如果是 pointerup, 则计算新的交互 ID,并分别设置到 pointerdownpointerup(以及稍后出现的 click)。

3.7. 初始化事件时序

当请求初始化事件时序,传入 eventprocessingStartinteractionId 时,执行以下步骤:
  1. 如果用于判断 event 是否纳入事件时序考虑的算法返回 false,则返回 null。

  2. timingEntry 为在 event相关领域中新建的 PerformanceEventTiming 对象。

  3. timingEntryname 设为 eventtype 属性值。

  4. timingEntryentryType 设为 "event"。

  5. timingEntrystartTime 设为 eventtimeStamp 属性值。

  6. timingEntryprocessingStart 设为 processingStart

  7. timingEntrycancelable 设为 eventcancelable 属性值。

  8. timingEntryinteractionId 设为 interactionId

  9. 返回 timingEntry

3.8. 完成事件时序

当请求完成事件时序,传入 timingEntryeventtargetprocessingEnd 时,执行以下步骤:
  1. timingEntry 为 null,则返回。

  2. relevantGlobaltarget相关全局对象

  3. relevantGlobal实现 Window, 则返回。

  4. timingEntryprocessingEnd 设为 processingEnd

  5. 断言 target 实现 Node

    注意:由于事件时序API支持的事件类型,该断言成立。

  6. timingEntry 的关联 eventTarget 设为 target

    注意:这会将 eventTarget 设为最后的事件目标。如果发生重定目标,则使用最靠近根节点的最后目标。

  7. eventtype 属性值为 pointerdown

    1. pendingPointerDownsrelevantGlobal待处理 pointerdown

    2. pointerIdeventpointerId

    3. pendingPointerDowns[pointerId] 存在:

      1. previousPointerDownEntrypendingPointerDowns[pointerId]。

      2. previousPointerDownEntry 添加到 relevantGlobal待入队条目

    4. pendingPointerDowns[pointerId] 设为 timingEntry

    5. window已触发 contextmenu 设为 false。

  8. 否则,若 eventtype 属性值为 keydown

    1. eventisComposing 属性值为 true

      1. timingEntry 添加到 relevantGlobal待入队条目

      2. 返回。

    2. pendingKeyDownsrelevantGlobal待处理 keydown

    3. codeeventkeyCode 属性值。

    4. pendingKeyDowns[code] 存在:

      1. previousKeyDownEntrypendingKeyDowns[code]。

      2. code 不为 229:

        1. window用户交互值 增加一个由用户代理选择的小数。

        2. previousKeyDownEntryinteractionId 设为 window用户交互值

        注意:229 是特殊情况,对应于输入法键盘事件。用户代理有时会多次发送这些事件,并不对应于长按某键。

      3. previousKeyDownEntry 添加到 window待入队条目

    5. pendingKeyDowns[code] 设为 timingEntry

  9. 否则:

    1. timingEntry 添加到 relevantGlobal待入队条目

3.9. 分发待处理事件时序条目

当请求分发待处理事件时序条目给一个 Document doc 时,执行以下步骤:
  1. windowdoc相关全局对象

  2. renderingTimestamp当前高精度时间

  3. 对于 window待入队条目中的每个 timingEntry

    1. 设置事件时序条目持续时间,传入 timingEntrywindowrenderingTimestamp

    2. timingEntryduration 属性值大于等于 16,则 入队 timingEntry

  4. 清空 window待入队条目

  5. 对于 window待处理 pointerdown中的所有值中的每个 pendingPointerDownEntry

    1. 设置事件时序条目持续时间,传入 pendingPointerDownEntrywindowrenderingTimestamp

  6. 对于 window待处理 keydown中的所有值中的每个 pendingKeyDownEntry

    1. 设置事件时序条目持续时间,传入 pendingKeyDownEntrywindowrenderingTimestamp

当请求设置事件时序条目持续时间,给定 PerformanceEventTiming timingEntryWindow windowDOMHighResTimeStamp renderingTimestamp 时,执行以下步骤:
  1. timingEntryduration 属性值非零,则返回。

  2. starttimingEntrystartTime 属性值。

  3. timingEntryduration 设为 DOMHighResTimeStamp 类型的 renderingTimestamp - start,粒度为 8ms 或更小。

  4. nametimingEntryname 属性值。

  5. 执行以下步骤以更新事件计数:

    1. eventCountswindoweventCounts

    2. 断言 eventCounts 包含 name

    3. 设定 eventCounts[name] 为 eventCounts[name] + 1。

  6. window已分发输入事件为 false,且 timingEntryinteractionId 不为 0,执行以下步骤:

    1. firstInputEntrytimingEntry 的副本。

    2. firstInputEntryentryType 设为 "first-input"。

    3. 入队 firstInputEntry

    4. window已分发输入事件 设为 true。

4. 安全与隐私注意事项

我们不希望为 Web 平台引入更多高精度定时器,因为这类定时器会带来安全隐患。 事件处理器的时间戳与 performance.now() 的精度相同。 由于 processingStartprocessingEnd 可以在不使用本 API 的情况下被计算出来, 暴露这些属性不会带来新的攻击面。 因此,duration 是唯一需要额外考虑的属性。

duration 具有 8 毫秒的粒度(通过四舍五入计算)。 因此,无法利用此时间戳生成高精度定时器。 但它确实引入了开发者以往无法直接获取的新信息:事件处理后像素绘制所需的时间。 我们认为在暴露该时间戳时不存在安全或隐私方面的担忧,尤其考虑到其粒度。 为了只暴露最有用且信息量最少的新信息,我们决定将粒度设为 8 毫秒。 这也能保证在 120Hz 显示器上获得较为精准的时序。

选择 104ms 作为 duration 的默认阈值,只是第一个大于 100ms 的 8 的倍数。 一个事件如果经四舍五入后的持续时间大于等于 104ms,则其未四舍五入前的持续时间必然大于等于 100ms。 这类事件未能在 100ms 内被处理,极可能对用户体验造成负面影响。

选择 16ms 作为 durationThreshold 的最小允许值,是因为这能满足典型场景需求, 即确保响应足够流畅。在 120Hz 显示器下,响应若跳过超过一帧,至少会达到 16ms,因此该用户输入对应的条目会在 API 中以最小值被暴露。

一致性

文档约定

一致性要求通过描述性断言和 RFC 2119 术语的组合表达。 在本文件规范性部分中,“MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、“MAY”和“OPTIONAL” 这些关键字应按照 RFC 2119 的说明进行解释。 但为了可读性,本规范中这些词不会全部用大写字母表示。

本规范的所有文本均为规范性内容,除非明确标注为非规范性部分、示例和注释。[RFC2119]

本规范中的示例以“例如”开头,或用 class="example" 与规范性文本区分, 如下所示:

这是一个说明性示例。

说明性注释以“注意”开头,并用 class="note" 与规范性文本区分, 如下所示:

注意,这是一个说明性注释。

一致性算法

作为算法一部分,以祈使句表达的要求(如“去除所有前导空格字符”或“返回 false 并终止这些步骤”),应按照用于引入算法的关键字(“must”、“should”、“may”等)含义解释。

以算法或具体步骤形式表达的一致性要求,可以以任何方式实现,只要最终结果是等效的。 特别是,本规范中定义的算法旨在易于理解,而不是高性能。 鼓励实现者进行优化。

索引

本规范定义的术语

引用定义的术语

参考文献

规范性引用

[DOM]
Anne van Kesteren. DOM 标准. 实时标准. URL: https://dom.spec.whatwg.org/
[HR-TIME-2]
Ilya Grigorik. 高精度时间 第二级. 2019年11月21日. 推荐标准. URL: https://www.w3.org/TR/hr-time-2/
[HTML]
Anne van Kesteren; 等. HTML 标准. 实时标准. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra 标准. 实时标准. URL: https://infra.spec.whatwg.org/
[PAINT-TIMING]
Ian Clelland; Noam Rosenthal. 绘制时序. 2025年5月17日. 工作草案. URL: https://www.w3.org/TR/paint-timing/
[PERFORMANCE-TIMELINE-2]
Nicolas Pena Moreno. 性能时序. 2025年5月21日. 候选推荐. URL: https://www.w3.org/TR/performance-timeline/
[POINTEREVENTS]
Jacob Rossi; Matt Brubeck. 指针事件. 2019年4月4日. 推荐标准. URL: https://www.w3.org/TR/pointerevents/
[POINTEREVENTS4]
Patrick Lauke; Robert Flack. 指针事件. 2025年5月1日. 工作草案. URL: https://www.w3.org/TR/pointerevents4/
[RFC2119]
S. Bradner. 用于RFC的关键字以指示需求级别. 1997年3月. 最佳当前实践. URL: https://datatracker.ietf.org/doc/html/rfc2119
[TOUCH-EVENTS]
Doug Schepers; 等. 触控事件. 2013年10月10日. 推荐标准. URL: https://www.w3.org/TR/touch-events/
[UIEVENTS]
Gary Kacmarcik; Travis Leithead. UI 事件. 2024年9月7日. 工作草案. URL: https://www.w3.org/TR/uievents/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL 标准. 实时标准. URL: https://webidl.spec.whatwg.org/

IDL 索引

[Exposed=Window]
interface PerformanceEventTiming : PerformanceEntry {
    readonly attribute DOMHighResTimeStamp processingStart;
    readonly attribute DOMHighResTimeStamp processingEnd;
    readonly attribute boolean cancelable;
    readonly attribute Node? target;
    readonly attribute unsigned long long interactionId;
    [Default] object toJSON();
};

[Exposed=Window]
interface EventCounts {
    readonly maplike<DOMString, unsigned long long>;
};

[Exposed=Window]
partial interface Performance {
    [SameObject] readonly attribute EventCounts eventCounts;
    readonly attribute unsigned long long interactionCount;
};

partial dictionary PerformanceObserverInit {
    DOMHighResTimeStamp durationThreshold;
};

MDN

EventCounts

Firefox89+SafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

Performance/eventCounts

Firefox89+SafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
Node.jsNone
MDN

PerformanceEventTiming/cancelable

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/interactionId

In only one current engine.

FirefoxNoneSafariNoneChrome96+
Opera?Edge96+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/processingEnd

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/processingStart

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/target

Firefox89+SafariNoneChrome85+
Opera?Edge85+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming/toJSON

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceEventTiming

Firefox89+SafariNoneChrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?