当毫秒不是毫秒的时候
#javascript #网络开发人员 #性能 #webperf

时间的起源

koude0是一个据称代表时间(从epoch中的毫秒)的值,当时已启动了当前文档或创建工人时。这允许将用于性能测量的高分辨率时间转换为“真实时间,也就是墙壁锁定时间,我们都知道和喜欢的时间。听起来很简单。但是

两个时钟的故事

测量性能时,我们通常会考虑两个时钟:单调时钟(例如koude1)和壁钟(例如koude2)。我们将单调时钟用于高分辨率性能指标,以及向用户显示时间,并与单个文档范围之外的时间同步。

这是看似代表时钟之间关系的公式:

new Date().valueOf() === 
    performance.timeOrigin + 
    performance.now()

此公式的问题是有时是正确的。除了分辨率的差异外,问题是该公式假设一个毫秒是毫秒。

什么是毫秒?

毫秒是相对于地球旋转的测量值。这是地球在轴上旋转的时间(又称每天),除以8,640,000(24小时 * 60分钟 * 60秒 * 1000)。问题在于地球的旋转速度不是恒定的,我们在计算机和电话上都没有测量它。

在全球范围内,我们所知道的UTC实际上是基于一组非常准确的原子时钟的标准,定期调整以匹配地球的旋转。
我们拥有的是real time clock(RTC),以类似于石英手表的方式测量时间。 performance.now()实际上是该实时时钟的振荡或滴答的计数,已归一定的时钟速度,并使用NTP协议定期调整以匹配UTC。

为了增加一些复杂性,RTC并不相同,并且操作系统处理的方式也有很大不同。

换句话说,没有准确的时钟,而毫秒意味着不同的东西,具体取决于它们的测量方式。

那么,为什么不使用壁时钟而忘记单调时钟呢?

由于它们如何测量时间和如何同步,因此我们作为Web开发人员可用的两个时钟都是不准确的,但以不同的方式 。单调时钟(仅依赖于我们的硬件随附的任何RTC,但是OS曝光单调时间)足够准确,足以在高分辨率下测量短持续时间,这非常适合性能基准测试。长时间长的壁时钟更好,并且跨系统同步,因为这些系统都使用NTP定期与UTC(彼此之间)同步。

那问题是什么?

使用单调时钟时,问题的根部出现,并在很长一段时间内将其缩放。例如,在活跃数分钟,小时或几天的网页中调用performance.now()。时间越多,并且取决于页面正在运行的系统以及文档一生中的任何时刻的睡眠,上面的公式变得越来越不准确,而performance.timeOrigin变得越来越降低,作为一种方式的有意义在单调时钟和壁时钟之间翻译。

在那些长期运行的会话中,人们经常惊讶于他们的性能时间表条目在由timeOrigin调整后与服务器或其他UTC对齐的时间不匹配的时间。

例如,请参见此chromium bug report
简而

那解决方案是什么?

没有神奇的解决方案。只要我们在手机中都没有科学级的原子钟,只要地球加速或放慢速度,时钟漂移就会是事实,并且将长的单调持续时间转换为UTC将带来令人惊讶的结果。

我们 can 做的是定期测量漂移,而不是依靠常数timeOrigin

好消息是,我们不需要新的API。

可变时间来源

,我们可以将时间来源视为是的变量,而不是依靠常数代表变量,并定期将其视为我们自己的变量:

// This is the inverse of the previous formula...
function variableTimeOrigin() {
 return new Date() - performance.now();
}

我们可以在文档的初始化时(如果我们想模仿performance.timeOrigin的行为),一次为每个perfortricterry,或者每当适合我们的用例时,我们可以每小时一次调用一次,一次每小时一次。但是,由于您将失去精确度(具有双重精确浮标的大数字),但不要以高分辨率进行调用。

如果您重新监视现场的性能,请考虑使用信标发送此值,并以您认为合适的任何方式调整仪表板。没有正确的解决方案,如何将时间表从不同的时钟叠加,检查对您有用的方法。
也许您已经这样做了。

要点

毫秒根据测量它们的时钟而变化。
因此,在长时间内不依靠单调时钟与壁时钟同步。
如果您需要在性能时间表和UTC之间关联,则可以偶尔测量可变的时间来源。

玩得开心!