【问题标题】:Current time is older than the previously saved time当前时间早于之前保存的时间
【发布时间】:2017-04-06 09:48:33
【问题描述】:

我的假设是时间总是向前流逝,但显然有时它不会以这种方式发生。

我有以下例子:

var LOOP_MS = 100;

var prevCall = +new Date();

setTimeout(function loop() {
    foobar();

    setTimeout(loop, LOOP_MS);
}, LOOP_MS);

function foobar() {
    var now = +new Date(),
        diff = now - prevCall;  // expected to be somewhere around LOOP_MS

    // do stuff
    console.log(diff);

    prevCall = now;
}

现在,大部分时间它都按预期工作,diff 显示的数字接近 100。当然,在现实生活中,我希望这个数字会上升,尤其是当用户的计算机处于执行一些繁重的操作。

我没想到的是看到一个负数,但它确实发生了。怎么可能?我错过了什么吗?我想这可能是由不同的时区引起的,但事实并非如此。我也在不同的浏览器(Chrome、Firefox、Safari)中看到它,并且差异值非常不一致:从 -9 到 -100 000。

它发生在大约 0.025% 的生产案例中,所以这不是一个大问题,但我想知道它到底怎么可能发生(即使在理论上)?

我想我设法通过在慢速 VM 中运行脚本并模拟高 CPU 负载在本地重现了几次,但我仍然不明白为什么该函数会显示负数(意思是 now早于prevCall)。

【问题讨论】:

  • 你能告诉我们哪个输入 prevCallnow 显示出这样的行为吗?
  • @GerardoFurtado 这是(new Date()).getTime()的快捷方式
  • @gurvinder372 我不确定我是否理解你的问题。整个代码在帖子里,没有输入。
  • 我发现这很有趣并设置了一个 plunker plnkr.co/edit/cqqBBmIEMg518ZEEXuys?p=preview。我无法用负数重现您的问题。运行时,数字始终至少为 100。
  • 正如@Hinrich 所说,无法重现此内容。也许你的硬件有问题。

标签: javascript time


【解决方案1】:

大多数计算机都配置为使用 NTP 服务器来设置系统时钟。

由于系统时钟是第一次正常设置,它将保持同步,无需更新。

有时(很少)由于各种原因系统时钟可能会不同步。

由于系统时钟与 NTP 服务器时间不匹配,因此会更新并可能会倒退。

NTP 服务(通常)被配置为避免时钟倒退:如果“间隙”足够小,则 NTP 守护进程尝试“减慢”系统时钟,直到它再次进入 sysnc。但正如刚才所说,这取决于时间间隔的配置和大小。

我认为上述所有原因在极少数情况下会导致您看到的问题。

你可能会觉得这很有趣:Is there a way to ensure ntp synced clock never moves backwards?


如果您使用的是 macOS,您可以尝试打开控制台并搜索 ntpd

在我的机器上(10.9.5 的 MBP)我看到几行这样的...

Apr  2 01:11:40 mac-di-paolo.local ntpd[46]: ntpd: wake time set -1.848017 s

...记录系统时钟调整。

【讨论】:

  • 我不确定有没有办法验证它,但听起来确实可行。
  • @DanielJF 我同意,因为它很难重现。但是有很多线索指向这个方向。
【解决方案2】:

prevCall 是一个具有通用名称的全局变量 - 是否有其他函数写入它?

【讨论】:

  • 不,这是页面上唯一的 JS。
【解决方案3】:

第一。你有一个不准确的等式,即使在高度准确的 IE 计时器中,它至少会在延迟报价上给出 -1 到 +1。所以这很正常。

第二。计时器的执行优先级较低,即使是最轻微的客户端鼠标页面交互也可能会使其间隔时间缩短几毫秒。

所有其他同步操作、函数和事件都会使它们(定时器)停止,并在给定间隔内造成更大的干扰。

【讨论】:

  • 嗯,你所经历的负面时间,可能只发生在 V8 机器上,考虑到计时器函数像字符串一样传递,它们可能会在过早编译时被分成两半,而不是由于一些暂停而放入堆栈过程,并且由于 chrome 具有完全“不稳定排序”的哈希值,因此这些值在发布时可能很容易切换顺序,然后你就可以得到一个负增量。
【解决方案4】:

实际上,通过更改计算机上的时间很容易做到这一点。

一般很难解决这个问题,但你可能会发现一些更具体的问题的巧妙方法。例如,如果您在网站上显示倒计时时钟,那么您的服务器可以说出 GMT 开始时间是什么,它认为“现在”是什么以及还剩多少秒。每当事情“出错”*时,您可以向您的服务器询问相同的信息,并根据该信息与机器上的本地时间进行比较。基本上,您可以使用服务器时间而不是前端时间作为参考点。

出错 * - 我的意思是,计时器变为负数或自上次执行以来已经过去了太多时间。过多的时间可能意味着 20 秒。

【讨论】:

  • 我想过这个场景,但是如果函数得到一个很高的负值,时区不应该改变吗?因为它不会发生。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 2018-11-04
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多