W3C

导航计时

W3C 推荐 2012年12月17日

此版本
https://w3org.cn/TR/2012/REC-navigation-timing-20121217/
最新版本
https://w3org.cn/TR/navigation-timing/
上一版本
https://w3org.cn/TR/2012/PR-navigation-timing-20120726/
编辑
王志恒 (Google Inc.) <>

请参阅本文件的勘误表,其中可能包含一些规范性更正。

另请参见译本


摘要

本规范定义了一个供 Web 应用访问与导航及元素相关的计时信息的接口。

关于本文档

本节描述本文档在发布时的状态。其他文档可能会取代本文档。当前的 W3C 出版物列表和本技术报告的最新修订版可在 https://w3org.cn/TR/ 的 W3C 技术报告索引中找到。

这是“导航计时规范”的 W3C 推荐稿。可在实现报告中查看 2012 年候选推荐阶段基于导航计时测试套件的实现情况。

请将评论发送至 public-web-perf@w3.org归档),邮件主题行开头请加上 [NavigationTiming]

本文件由Web Performance 工作组编写。可查看与上一稿的差异文档

本文件已由 W3C 会员、软件开发人员以及其他 W3C 小组和利害关系方审阅,并由总干事认可为 W3C 推荐标准。这是一个稳定的文档,可以用作参考材料或从另一个文档中引用。W3C 发布推荐标准的角色是引起对规范的关注并促进其广泛部署。这增强了 Web 的功能和互操作性。

本文件由遵循2004 年 2 月 5 日 W3C 专利政策的组发布。W3C 维护一份公开专利披露列表,其中也包含披露专利的说明。若个人实际了解某项专利且认为其中含有关键权利要求,必须依据专利政策第 6 节进行披露。

目录

  1. 1 简介
  2. 2 合规性要求
  3. 3 术语
  4. 4 导航计时
    1. 4.1 引言
    2. 4.2 PerformanceTiming 接口
    3. 4.3 PerformanceNavigation 接口
    4. 4.4 window.performance 属性
  5. 5 处理过程
    1. 5.1 处理模型
    2. 5.2 垃圾回收
    3. 5.3 单调时钟
    4. 5.4 厂商前缀
  6. 6 隐私
    1. 6.1 信息披露
    2. 6.2 跨目录访问
  7. 7 安全性
    1. 7.1 检测代理服务器
    2. 7.2 通过替换计时对象进行篡改
  8. 8 参考文献
    1. 8.1 规范性参考文献
    2. 8.2 信息性参考文献
  9. 致谢 (Acknowledgements)

1 简介

本节是非规范性的。

用户延迟是 Web 应用的重要质量基准。虽然诸如[JSMEASURE] 中描述的脚本机制可以为应用内部的用户延迟测量提供完整的检测手段,但在很多情况下,它们无法提供完整的端到端延迟视图。

例如,下面的脚本展示了一种朴素的测量页面完整加载时间的尝试。

<html>
<head>
<script type="text/javascript">

var start = new Date().getTime();
function onLoad() {
  var now = new Date().getTime();
  var latency = now - start;
  alert("page loading time: " + latency);
}

</script>
</head>
<body onload="onLoad()">
<!- Main page body goes from here. -->
</body>
</html>

该脚本在中的第一段 JavaScript 执行后才开始计算页面加载时间,却没有提供从服务器获取页面所耗费的时间信息。

为了解决获取完整用户体验信息的需求,本文档引入了PerformanceTiming 接口。该接口允许 JavaScript 机制在应用内部提供完整的客户端延迟测量。借助所提议的接口,前面的示例可被修改为测量用户感知的页面加载时间。

下面的脚本计算自最近一次导航开始以来加载页面所耗费的时间。

<html>
<head>
<script type="text/javascript">
function onLoad() {
  var now = new Date().getTime();
  var page_load_time = now - performance.timing.navigationStart;
  alert("User-perceived page loading time: " + page_load_time);
}

</script>
</head>
<body onload="onLoad()">
<!- Main page body goes from here. -->
</body>
</html>

本工作提供的接口并不旨在作为用户代理的任何形式的性能基准。

2 合规性要求

本规范中的所有图表、示例和注释均为非规范性内容,明确标记为非规范性的章节亦如此。本规范中的所有其他内容均为规范性内容。

本文档规范部分中的关键字 “MUST”、 “MUST NOT”、 “REQUIRED”、 “SHOULD”、 “SHOULD NOT”、 “RECOMMENDED”、 “MAY” 与 “OPTIONAL” 应按照RFC 2119 中的描述进行解释。为便于阅读,这些词在本规范中未全部使用全大写形式。

作为算法一部分的祈使语气要求(例如“去除任何前导空格字符”或“返回 false 并中止这些步骤”)应根据引入算法时使用的关键词(“必须”、“应该”、“可以”等)进行解释。

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

以算法或具体步骤表述的一致性要求可以以任何方式实现,只要最终结果等效即可。(特别说明,本规范中定义的算法旨在易于遵循,而非旨在达到高性能。)

本规范中的 IDL 片段必须按符合 Web IDL 规范的要求进行解释。[Web IDL]

3 术语

构造 “a Foo object”(其中 Foo 实际上是一个接口)有时会被用来代替更准确的 “实现接口 Foo 的对象”。

术语 “navigation” 指的是导航行为。

术语 “JavaScript” 用于指代ECMA‑262,而非官方术语 ECMAScript,因为 JavaScript 更为大众所熟知。

在本文档中,时间以自 1970 年 1 月 1 日午夜(UTC)起的毫秒为单位进行计量。请注意,Navigation Timing 2 规范允许使用亚毫秒分辨率来访问与导航相关的计时信息。

4 导航计时

4.1 引言

本节为非规范性内容

本规范引入了一个为 Web 应用提供计时相关信息的接口。它并不涉及 Web 应用如何利用这些接口收集、存储和报告所提供的信息。

4.2 PerformanceTiming 接口

interface PerformanceTiming {
  readonly attribute unsigned long long navigationStart;
  readonly attribute unsigned long long unloadEventStart;
  readonly attribute unsigned long long unloadEventEnd;
  readonly attribute unsigned long long redirectStart;
  readonly attribute unsigned long long redirectEnd;
  readonly attribute unsigned long long fetchStart;
  readonly attribute unsigned long long domainLookupStart;
  readonly attribute unsigned long long domainLookupEnd;
  readonly attribute unsigned long long connectStart;
  readonly attribute unsigned long long connectEnd;
  readonly attribute unsigned long long secureConnectionStart;
  readonly attribute unsigned long long requestStart;
  readonly attribute unsigned long long responseStart;
  readonly attribute unsigned long long responseEnd;
  readonly attribute unsigned long long domLoading;
  readonly attribute unsigned long long domInteractive;
  readonly attribute unsigned long long domContentLoadedEventStart;
  readonly attribute unsigned long long domContentLoadedEventEnd;
  readonly attribute unsigned long long domComplete;
  readonly attribute unsigned long long loadEventStart;
  readonly attribute unsigned long long loadEventEnd;
};

navigationStart 属性

该属性必须返回用户代理在完成对前一个文档的卸载提示后立即的时间。如果不存在前一个文档,则该属性必须返回与fetchStart 相同的值。

unloadEventStart 属性

如果前一个文档与当前文档拥有相同的 [IETF RFC 6454],则该属性必须返回用户代理在启动前一个文档的unload 事件之前的时间。如果不存在前一个文档,或前一个文档的源与当前文档不同,则该属性必须返回 0。

unloadEventEnd 属性

如果前一个文档与当前文档具有相同的同源,则该属性必须返回用户代理在完成前一个文档的unload 事件之后的时间。如果不存在前一个文档,或前一个文档的源不同,或 unload 尚未完成,则该属性必须返回 0。

如果在导航过程中出现 HTTP 重定向或等效行为,且所有重定向或等效行为并非来自同一,则 unloadEventStartunloadEventEnd 必须返回 0。

redirectStart 属性

如果在导航过程中出现 HTTP 重定向或等效行为,且所有重定向或等效行为均来自同一,则该属性必须返回发起重定向的fetchStart 时间。否则,该属性必须返回 0。

redirectEnd 属性

如果在导航过程中出现 HTTP 重定向或等效行为,且所有重定向和等效行为均来自同一,则该属性必须返回接收最后一次重定向响应的最后一个字节之后的时间。否则,该属性必须返回 0。

fetchStart 属性

如果要使用 HTTP GET或等效方式获取新资源,则 fetchStart 必须返回用户代理在开始检查任何相关应用缓存之前的时间。否则,必须返回用户代理开始获取该资源的时间。

domainLookupStart 属性

该属性必须返回用户代理在开始对当前文档进行域名解析之前的时间。如果使用了持久连接 [RFC 2616],或当前文档是从相关应用缓存或本地资源中获取的,则该属性必须返回与fetchStart 相同的值。

domainLookupEnd 属性

该属性必须返回用户代理在完成对当前文档的域名解析之后的时间。如果使用了持久连接 [RFC 2616],或当前文档是从相关应用缓存或本地资源中获取的,则该属性必须返回与fetchStart 相同的值。

本节是非规范性的。

检查并从HTTP 缓存 [RFC 2616] 中检索内容是获取过程的一部分。它由 requestStartresponseStartresponseEnd 属性覆盖。

示例

在用户代理已将域信息缓存在本地的情况下,domainLookupStart 与 domainLookupEnd 表示用户代理从缓存中开始并结束域数据检索的时间。

connectStart 属性

该属性必须返回用户代理在开始与服务器建立连接以获取文档之前的时间。如果使用了持久连接 [RFC 2616],或当前文档是从相关应用缓存或本地资源中获取的,则该属性必须返回domainLookupEnd 的值。

connectEnd 属性

该属性必须返回用户代理在完成与服务器建立连接以获取当前文档之后的时间。如果使用了持久连接 [RFC 2616],或当前文档是从相关应用缓存或本地资源中获取的,则该属性必须返回domainLookupEnd 的值。

如果传输连接失败且用户代理重新打开连接,connectStartconnectEnd 应返回新连接对应的数值。

connectEnd 必须同时包含建立传输连接的时间间隔以及诸如 SSL 握手和 SOCKS 认证等其他时间间隔。

secureConnectionStart 属性

该属性为可选项。未提供此属性的用户代理必须将其设为 undefined。当属性可用且当前页面的方案HTTPS 时,必须返回用户代理在开始对当前连接进行安全握手之前的时间。如果属性可用但未使用 HTTPS,则必须返回 0。

requestStart 属性

该属性必须返回用户代理在开始向服务器(或相关应用缓存、本地资源)请求当前文档之前的时间。

如果在请求发送后传输连接失败且用户代理重新打开连接并重新发送请求,requestStart 应返回新请求对应的数值。

此接口不包含表示发送请求完成的属性,例如 requestEnd。

responseStart 属性

该属性必须返回用户代理在收到服务器(或相关应用缓存、本地资源)响应的第一个字节之后的时间。

responseEnd 属性

该属性必须返回用户代理在收到当前文档的最后一个字节之后,或在传输连接关闭之前(两者取先到者)的时间。此处的文档可以来自服务器、相关应用缓存或本地资源。

domLoading 属性

该属性必须返回用户代理在将当前文档就绪状态设为“loading” 之前的时间。

domInteractive 属性

该属性必须返回用户代理在将当前文档就绪状态设为“interactive” 之前的时间。

domContentLoadedEventStart 属性

该属性必须返回用户代理在触发 DOMContentLoaded 事件Document 之前的时间。

domContentLoadedEventEnd 属性

该属性必须返回文档的DOMContentLoaded 事件完成后的时间。

domComplete 属性

该属性必须返回用户代理在将当前文档就绪状态设为“complete” 之前的时间。

如果当前文档就绪状态多次变更为相同的状态,则 domLoadingdomInteractivedomContentLoadedEventStartdomContentLoadedEventEnddomComplete 必须返回对应的首次就绪状态变更的时间。

loadEventStart 属性

该属性必须返回用户代理在触发当前文档的 load 事件之前的时间。如果 load 事件尚未触发,则必须返回 0。

loadEventEnd 属性

该属性必须返回当前文档的 load 事件完成时的时间。如果 load 事件未触发或尚未完成,则必须返回 0。

4.3 PerformanceNavigation 接口

interface PerformanceNavigation {
  const unsigned short TYPE_NAVIGATE = 0;
  const unsigned short TYPE_RELOAD = 1;
  const unsigned short TYPE_BACK_FORWARD = 2;
  const unsigned short TYPE_RESERVED = 255;
  readonly attribute unsigned short type;
  readonly attribute unsigned short redirectCount;
};

type 属性

该属性必须返回当前浏览上下文中最近一次非重定向导航的类型。其取值必须为以下导航类型之一。

TYPE_NAVIGATE

用户点击链接、在地址栏输入 URL、表单提交,或通过脚本发起的除 TYPE_RELOAD 与 TYPE_BACK_FORWARD 之外的其他操作导致的导航。

TYPE_RELOAD

通过刷新操作或 location.reload() 方法触发的导航。

TYPE_BACK_FORWARD

通过历史记录遍历操作触发的导航。

TYPE_RESERVED

未在上述值中定义的其他导航类型。

客户端重定向(例如使用Refresh 元指令)不被本规范视为 HTTP 重定向或等效行为。此类情况下,type 属性应返回合适的值,例如当前页面被重新加载时返回 TYPE_RELOAD,若导航至新 URL 则返回 TYPE_NAVIGATE

redirectCount 属性

该属性必须返回当前浏览上下文中自最近一次非重定向导航以来的重定向次数。如果没有重定向,或任意一次重定向的源不同于目标文档的,则该属性必须返回 0。

4.4 window.performance 属性

HTML5 规范定义了Window 接口[HTML5],本规范在其基础上进行扩展。

interface Performance {
  readonly attribute PerformanceTiming timing;
  readonly attribute PerformanceNavigation navigation;
};

partial interface Window {
  [Replaceable] readonly attribute Performance performance;
};

window.performance 属性提供了一个用于托管与性能相关属性的空间。

timing 属性

timing 属性表示自最近一次非重定向导航以来与浏览上下文相关的计时信息。该属性由PerformanceTiming 接口定义。

navigation 属性

navigation 属性由PerformanceNavigation 接口定义。

5 处理过程

5.1 处理模型

当前文档的 Window 对象创建完成之前,window.performance.timing 与 window.performance.navigation 中的所有属性均不应被写入,尽管在后续步骤中会引用这些属性以便描述。

用户代理可以为用户提供禁用 window.performance.timing 与 window.performance.navigation 接口的选项。当这些接口被禁用时,window.performance.timing 与 window.performance.navigation 必须返回 null。

示例

用户代理可以在创建当前文档对应的 Window 对象之前维护 PerformanceTiming 与 PerformanceNavigation 实例;当 Window 对象创建完成后,用这些实例替换 window.performance.timing 与 window.performance.navigation。

图示

此示意图为非规范性内容。

下图展示了由PerformanceTiming 接口和PerformanceNavigation 接口(带或不带重定向)定义的计时属性。带下划线的属性在涉及不同的文档导航时可能不可用。用户代理可在计时点之间执行内部处理,从而导致非规范性的间隔。

Timing attributes

  1. 如果因以下任意原因导致导航被中止,请在不更改 window.performance.timing 与 window.performance.navigation 中属性值的前提下终止后续步骤。
    1. 由于沙箱化导航浏览上下文标志沙箱化顶级导航浏览上下文标志,或已有尝试导航浏览上下文,导致导航被中止。
    2. 导航因页面内的片段标识符而被触发。
    3. 新资源将由某种内联内容处理。
    4. 新资源将通过不影响浏览上下文的机制处理。
    5. 用户拒绝允许文档卸载
  2. 在用户代理提示卸载前一个文档后,立即记录当前时间为navigationStart
  3. 如果尚未设置,则在 window.performance.navigation.type 中记录当前导航类型。
    1. 如果导航是通过点击链接、在地址栏输入 URL、表单提交或除location.reload() 之外的脚本操作发起的,则导航类型为TYPE_NAVIGATE
    2. 如果导航是由meta refreshlocation.reload() 方法或其他等效操作触发的,则导航类型为TYPE_RELOAD
    3. 如果导航是由历史记录遍历触发的,则导航类型为TYPE_BACK_FORWARD
    4. 否则,导航类型为TYPE_RESERVED
  4. 如果当前文档与前一个文档的源不同,则将 unloadEventStartunloadEventEnd 均设为 0,然后转到步骤 6。否则,记录 unloadEventStart 为卸载事件触发前的时间。
  5. 卸载事件完成后,立即记录当前时间为unloadEventEnd
  6. 如果新资源使用 HTTP GET或等效方式获取,则在用户代理检查相关应用缓存之前,记录当前时间为fetchStart。否则,在用户代理开始获取过程之前记录当前时间为fetchStart
  7. domainLookupStartdomainLookupEndconnectStartconnectEnd 均等于fetchStart
  8. 如果资源是从相关应用缓存或本地资源(包括HTTP 缓存)中获取,则转到步骤 13
  9. 如果不需要域名解析,则转到步骤 11。否则,在用户代理开始域名解析之前记录时间为domainLookupStart
  10. 在域名解析成功完成后立即记录时间为domainLookupEnd。用户代理可能需要多次重试才能成功。如果域名解析失败,则中止后续步骤。
  11. 如果使用持久传输连接获取资源,则令 connectStartconnectEnd 均等于 domainLookupEnd。否则,在向服务器发起连接之前记录时间为connectStart,在与服务器或代理的连接建立完成后记录时间为connectEnd。用户代理可能需要多次重试。如果无法建立连接,则中止后续步骤。
  12. 在步骤 11 中,若用户代理支持 secureConnectionStart 属性,则还应执行以下附加步骤。
    1. 如果当前文档的方案为 HTTPS,用户代理必须在安全握手开始之前记录时间为secureConnectionStart
    2. 如果当前文档的方案不是 HTTPS,用户代理必须将secureConnectionStart 的值设为 0。
  13. 在用户代理开始发送文档请求之前,记录当前时间为requestStart
  14. 在用户代理收到响应的第一个字节后立即记录时间为responseStart
  15. 在收到响应的最后一个字节后立即记录时间为responseEnd

    如果用户代理发送请求或接收完整响应失败且需要重新打开连接,则返回步骤 11

    示例

    当启用持久连接 [RFC 2616] 时,用户代理可能会首先尝试重用已打开的连接来发送请求,即使该连接可能已被异步关闭。此时,connectStart、connectEnd 与 requestStart 应反映重新打开的连接的计时信息。

  16. 如果获取的资源导致 HTTP 重定向或等效行为,则
    1. 若当前文档与被重定向至的文档源不同,则将 redirectStartredirectEndunloadEventStartunloadEventEndredirectCount 均设为 0。随后返回步骤 6 继续处理新资源。
    2. 如果先前的重定向涉及的文档与当前文档源不同,则将 redirectStartredirectEndunloadEventStartunloadEventEndredirectCount 均设为 0。随后返回步骤 6 继续处理新资源。
    3. redirectCount 加 1。
    4. 如果 redirectStart 的值为 0,则令其等于fetchStart
    5. redirectEnd 等于responseEnd 的值。
    6. 将 window.performance.timing 中除 navigationStartredirectStartredirectEndunloadEventStartunloadEventEnd 之外的所有属性均设为 0。
    7. 返回步骤 6,继续处理新资源。
  17. 在用户代理将当前文档就绪状态设为 “loading” 之前,记录时间为domLoading
  18. 在用户代理将当前文档就绪状态设为 “interactive” 之前,记录时间为domInteractive
  19. 在用户代理触发文档的DOMContentLoaded 事件之前,记录时间为domContentLoadedEventStart
  20. DOMContentLoaded 事件完成之后,记录时间为domContentLoadedEventEnd
  21. 在用户代理将当前文档就绪状态设为 “complete” 之前,记录时间为domComplete
  22. 在用户代理触发 load 事件之前,记录时间为loadEventStart
  23. 在用户代理完成 load 事件之后,记录时间为loadEventEnd

5.2 垃圾回收

从 window 对象到其 window.performance.timing 与 window.performance.navigation 对象存在隐式强引用

5.3 单调时钟

计时属性的值必须单调递增,以确保在导航期间系统时钟的调整不会导致计时属性出现偏差。任意两个按时间顺序记录的计时属性之间的差值永不为负。对于所有导航(包括子文档导航),用户代理必须在根文档导航开始时记录系统时钟,并以单调时钟(从导航开始算起的已逝时间)定义后续的计时属性。

5.4 厂商前缀

不鼓励使用厂商专有的用户代理扩展。如需此类扩展(例如用于实验),厂商必须采用以下扩展机制。

6 隐私

本节是非规范性的。

6.1 信息披露

通过精心构造的计时攻击,可能会泄露终端用户的浏览和活动历史。例如,卸载时间会透露前一个页面执行其 unload 处理程序所需的时长,从而可能推断用户的登录状态。通过在访问涉及前一次导航的计时信息时强制相同的 origin 策略,这类攻击已得到缓解。

宽松的同源策略无法为跨文档的未经授权访问提供足够的保护。在共享托管环境中,未受信任的第三方可以在相同的 IP 地址但不同端口上托管 HTTP 服务器。

6.2 跨目录访问

不同页面共享同一主机名,例如在用户生成内容站点上由不同作者提供的内容,被视为同一来源,因为没有通过路径名限制访问的机制。在这些页面之间进行导航时,后续页面可以访问前一个页面的计时信息,例如重定向和卸载事件的时间。

7 安全性

本节是非规范性的。

7.1 检测代理服务器

如果在用户代理和 Web 服务器之间部署了代理,则 connectStartconnectEnd 属性之间的时间间隔表示用户代理与代理之间的延迟,而非与 Web 服务器之间的延迟。这样,Web 服务器可能推断出代理的存在。对于 SOCKS 代理,该时间间隔包括代理的身份验证时间以及代理连接到 Web 服务器所花费的时间,这会掩盖代理检测。若使用 HTTP 代理,用户代理可能根本不知道代理服务器的存在,因此并非总能缓解此类攻击。

7.2 通过替换计时对象进行篡改

window.performance 对象是可替换的,以避免与使用相同对象的现有页面产生冲突。这样,第三方可以替换该对象,而依赖本规范所描述接口的脚本将失效。

8 参考文献

8.1 规范性参考文献

[IETF RFC 2119]
Key words for use in RFCs to Indicate Requirement Levels,Scott Bradner,作者。Internet Engineering Task Force,1997年3月。可在 http://www.ietf.org/rfc/rfc2119.txt 获取。
[IETF RFC 2616]
Hypertext Transfer Protocol -- HTTP/1.1,R. Fielding 等,作者。Internet Engineering Task Force,1999年6月。可在 http://www.ietf.org/rfc/rfc2616.txt 获取。
[IETF RFC 6454]
The Web Origin Concept,Adam Barth,作者。Internet Engineering Task Force,2011年12月。可在 http://www.ietf.org/rfc/rfc6454.txt 获取。
[ECMA-262]
ECMAScript Language Specification,第 5.1 版。ECMA International,标准 ECMA-262,2011年6月。此版本的 ECMAScript 语言可在 http://www.ecma-international.org/publications/standards/Ecma-262.htm 获取。
[HTML5]
HTML5,Robin Berjon 等,编辑。World Wide Web Consortium,2012年12月。此版本的 HTML5 可在 https://w3org.cn/TR/html5/ 获取。HTML5 最新编辑草案 位于 https://w3org.cn/html/wg/drafts/html/CR/。
[Web IDL]
Web IDL,Cameron McCormack,编辑。World Wide Web Consortium,2012年4月。此版本的 Web IDL 规范可在 https://w3org.cn/TR/2012/CR-WebIDL-20120419/ 获取。Web IDL 最新版本 位于 https://w3org.cn/TR/WebIDL/。

8.2 信息性参考文献

[JSMEASURE]
Measuring Client-Perceived Response Times on the WWW,R. Rajamony 和 M. Elnozahy,The Proceedings of the 3rd USENIX Symposium on Internet Technologies and Systems (USITS),2001年3月。
[Navigation Timing 2]
Navigation Timing 2,Jatinder Mann, Arvind Jain,编辑。World Wide Web Consortium,未出版

致谢 (Acknowledgements)

我要向所有在本草案上与我联系过的人员表达诚挚的谢意,包括 Anderson Quach、Alex Russell、Alois Reitbauer、Annie Sullivan、Christian Biesinger、Darin Fisher、Eric Lawrence、James Simonsen、Jatinder Mann、Jason Sobel、Jason Weber、Jonas Sicking、Kyle Scholz、Lenny Rachitsky、Nic Jansma、Richard Rabbat、Sergey Novikov、Sigbjørn Vik、Steve Souders、Tony Gentilcore,感谢他们的审阅和反馈。