获取导航计时 backward/forward 兼容 - 从纪元转换为 HR 时间

Get Navigation Timing backward/forward compatible - Convert from epoch to HR time

让我们通过 www.w3.org 的注释进行介绍,其中包括两个重要的 link 以供比较。

The PerformanceTiming interface was defined in [NAVIGATION-TIMING] and is now considered obsolete. The use of names from the PerformanceTiming interface is supported to remain backwards compatible, but there are no plans to extend this functionality to names in the PerformanceNavigationTiming interface defined in [NAVIGATION-TIMING-2] (or other interfaces) in the future.

我做了一个函数来获取一个导航时间,它应该是向后和向前兼容的,因为我们正处于转换到 2 级的中间时代。所以这个函数 从事件名称 在 Chrome 中有效,但在 Firefox 中无效:

function nav(eventName) {
  var lev1 = performance.timing; //deprecated unix epoch time in ms since 1970
  var lev2 = performance.getEntriesByType("navigation")[0]; //ms since page started to load. (since performance.timing.navigationStart)
  var nav = lev2 || lev1; //if lev2 is undefined then use lev1
  return nav[eventName]
}

说明:当没有 "navigation" 条目时,这会回退到已弃用的导航计时方式,该方式基于 Unix epoch time time in milliseconds since 1970 (lev1), while the new way (lev2) is HR time 自当前文档导航开始加载以来的毫秒数,与始终具有 HR 时间格式的用户计时一起使用时很有用。

如何在所有情况下得到函数return HR时间?

当我看到一个超过 10 位数字且没有句点的数字时,我知道这是从已弃用的 Navigation Timing level 1 获得的时间。所有其他测试用例都给出小数点数字,这意味着它是精度更高的 HR 时间。最大的问题是它们 不同 time origin

我经历了困惑、试验错误和沮丧的搜索(MDN 尚未更新到 2 级)以确认并声明:

如何转换unix epoch time to HR time?


已解决 .:

在 Amadan 的帮助下更正了代码。
请参阅接受的答案中的评论。

function nav(eventName, fallback) {
  var lev1 = performance.timing; //deprecated unix epoch time in ms since 1970
  var lev2 = performance.getEntriesByType("navigation")[0]; //ms since page started to load
  var nav = lev2 || lev1; //if lev2 is undefined then use lev1
  if (!nav[eventName] && fallback) eventName = fallback

  // approximate t microseconds it takes to execute performance.now()
  var i = 10000, t = performance.now()
  while(--i) performance.now()
  t = (performance.now() - t)/10000 // < 10 microseconds

  var oldTime = new Date().getTime(), 
      newTime = performance.now(),
      timeOrigin = performance.timeOrigin? 
                   performance.timeOrigin: 
                   oldTime - newTime - t; // approximate

  return nav[eventName] - (lev2? 0: timeOrigin);
  // return nav[eventName] - (lev2? 0: lev1.navigationStart); //alternative?
}

在使用旧时序lev1的情况下performance.timeOrigin减少
如果浏览器没有它,则通过减少 performance.now() the time since timeOrigin, from (new Date().getTime()) 自 Unix 纪元 的时间来近似 timeOrigin 导致 自 Unix 以来的 timeOrigin 时间纪元。显然这是定义,尽管 link 对此有点含糊。我通过测试确认,我相信答案。希望 w3c 对 timeOrigin 的定义比以下更好:性能测量开始时间的高分辨率时间戳

函数 returned 值表示自时间原点以来经过的时间。

在大多数情况下可能微不足道,但删除了执行 performance.now() 所花费的测量时间 t 以近似同时执行。

我在我的 Raspberry Pi 上测得 t 将近 10 微秒,这在各种循环大小下都相当稳定。但是我的 Lenovo 在测试更大的循环大小时时并没有精确地四舍五入小数点并且 t 上的时间更短。


在最后一行代码中注释掉了替代解决方案
弃用的 performance.timing.navigationStart:

representing the moment, in miliseconds since the UNIX epoch, right after the prompt for unload terminates on the previous document in the same browsing context. If there is no previous document, this value will be the same as PerformanceTiming.fetchStart

因此,要检查当前文档(忽略任何以前的文档),请使用已弃用的 performance.timing.fetchStart:

representing the moment, in miliseconds since the UNIX epoch, the browser is ready to fetch the document using an HTTP request. This moment is before the check to any application cache.

如果浏览器只理解它,那么使用已弃用的 属性 当然是正确的。当 getEntriesByType 中未定义 "navigation" 时使用,否则有 good browser support


return:

之前通过这一行快速检查彼此确认
console.log(performance.timeOrigin + '\n' + lev1.navigationStart + '\n' + lev1.fetchStart)

结果在我的 Chrome

中看起来像这样

1560807558225.1611
1560807558225
1560807558241

只有浏览器支持HR时间2才可以:

let unixTime = hrTime + performance.timeOrigin;

let hrTime = unixTime - performance.timeOrigin;

然而,performance通常用于时间差异,它不关心绝对时间戳的来源。

对于不支持 HR 时间 2 的浏览器,或者 "support" 它 half-heartedly 的浏览器,你可以这样伪装它:

const hrSyncPoint = performance.now();
const unixSyncPoint = new Date().getTime();
const timeOrigin = unixSyncPoint - hrSyncPoint;

它不是 super-exact,但对于大多数用途应该足够好(在我的系统上,performance.timeOrigin - timeOrigin 是 sub-millisecond)。