【问题标题】:Monotonically increasing time in JavaScript?在 JavaScript 中单调增加时间?
【发布时间】:2011-09-01 15:12:33
【问题描述】:

在 JavaScript 中获得单调增加时间的最佳方法是什么?我希望有像 Java 的 System.nanoTime() 这样的东西。

Date() 显然不行,因为它受系统时间变化的影响。

换句话说,我想要的是a 总是

a = myIncreasingTime.getMilliseconds();
...
// some time later, maybe seconds, maybe days
b = myIncreasingTime.getMilliseconds();

充其量,即使在Date() 中使用 UTC 函数,它也会返回它认为正确的时间,但如果有人将时间向后设置,下一次调用 Date() 可能会返回一个较小的值。 System.nanoTime() 不受此限制(至少在系统重新启动之前不会)。

修改: [2012-02-26:不打算影响原来的问题,有赏金]

我对知道“墙上时间”不感兴趣,我想知道 经过 时间的准确度,Date() 不可能提供。

【问题讨论】:

  • W3Schools 显示类似的内容。
  • 会话是什么意思?您在哪里运行此代码(浏览器、服务器)?
  • 对不起,我措辞不好。希望我刚刚添加的更改更清晰。
  • @xyu:w3schools 并不是一个真正的好网站 - w3fools.com - 他们将字符串传递给 setTimeout 的事实清楚地证明了这一点。
  • @ThiefMaster 是的,我知道。但我的意思是使用setTimeout 增加变量的想法。

标签: javascript timer


【解决方案1】:

您可以使用 window.performance.now() - 自 Firefox 15 和 window.performance.webkitNow() - Chrome 20]

var a = window.performance.now();
//...
var delay = window.performance.now() - a;

【讨论】:

【解决方案2】:

您可以包装 Date()Date.now() 以强制它是单调的(但不准确)。草图,未经测试:

var offset = 0;
var seen = 0;
function time() {
  var t = Date.now();
  if (t < seen) {
    offset += (seen - t);
  }
  seen = t;
  return t + offset;
}

如果系统时钟在给定时刻被调回,那么似乎没有经过任何时间(并且包含该间隔的经过时间将不正确),但您至少不会有负增量。如果没有回退,则返回与 Date.now() 相同的值。

如果您正在编写游戏模拟循环,这可能是一个合适的解决方案,例如,time() 被非常频繁地调用 - 最大错误是回调次数乘以调用之间的间隔。如果您的应用程序不自然地这样做,您可以在 setInterval 上显式调用它,比如说(假设它不受系统时钟的影响),以牺牲一些 CPU 时间为代价来保持准确性。


也有可能将时钟设置为向前,这不会阻止单调性,但可能会产生同样不良的影响(例如,游戏花费太长时间试图一次赶上其模拟)。然而,这与机器已经睡了一段时间并没有特别的区别。如果需要这样的保护,它只意味着改变现有条件旁边的条件,并为可接受的进度设置一个恒定阈值:

if (t > seen + leapForwardMaximum) {
  offset += (seen - t) + leapForwardMaximum;
}

我建议将leapForwardMaximum 设置为超过 1000 毫秒,因为例如,Chrome(如果我没记错的话)会限制后台选项卡中的计时器每秒触发不超过一次。

【讨论】:

  • 是的,很好,按照我最初的要求回答了。我已经修改了我的原始问题以添加准确性要求。
  • 一种明显的评论,对于原始问题的提问方式来说不是问题,但对于某些人来说可能很重要:此解决方案不处理用户将时钟向前设置的情况,即它不会阻止返回的时间出现较大的正向跳跃。
  • @MarkusA。这似乎值得讨论,所以我添加了一个部分。
【解决方案3】:

Javascript 本身没有任何访问 nanoTime 的功能。您可以加载一个 java-applet 来获取该信息,就像 benchmark.js 所做的那样。也许@mathias 可以阐明他们在那里做了什么……

【讨论】:

    【解决方案4】:

    Firefox 为 setTimeout 提供了“延迟”参数... 这是实现单调递增时间计数器的方法之一。

    var time = 0;
    
    setTimeout(function x(actualLateness) {
      setTimeout(x, 0);
      time += actualLateness;
    }, 0);
    

    【讨论】:

    • setTimeout 不保证最大延迟。该参数仅指定最小值。使用 setTimeout 无法最终确定实际经过的时间量。
    • 参见developer.mozilla.org/en/DOM/window.setTimeout, >> 注意:在 Gecko 13 (Firefox 13.0 / Thunderbird 13.0) 之前,Gecko 向回调例程传递了一个额外的参数,以毫秒为单位指示超时的“实际延迟” .这个非标准参数不再传了,我更新了答案
    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 2015-10-01
    • 2018-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-01
    相关资源
    最近更新 更多