JavaScript中的微秒计时

JavaScript中是否有微秒分辨率的定时function?

我知道Chrome的timer.js ,并希望将有其他友好的浏览器,如火狐,Safari浏览器,歌剧,主显节,Konqueror等解决scheme。我不支持任何IE的兴趣,但答案包括 IE浏览器受欢迎的。

(鉴于JS中毫秒时序精确度不佳,我不会屏住呼吸这个!)

更新:timer.js广告微秒的分辨率,但它只是毫秒读数乘以1,000。 通过testing和代码检查进行validation。 失望。 :[

正如在Mark Rejhon的回答中提到的那样,在现代浏览器中有一个API提供了亚毫秒级分辨率的定时数据到W3C高分辨率定时器 ,也就是window.performance.now()

now()比传统的Date.getTime()有两个重要的好处:

  1. now()是一个具有亚毫秒分辨率的双精度值,表示从页面导航开始以来的毫秒数。 它返回分数中的微秒数(例如,1000.123的值是1秒和123微秒)。

  2. now()是单调递增的。 这很重要,因为Date.getTime()可能在后续调用中向前或向后跳转。 值得注意的是,如果操作系统的系统时间被更新(例如primefaces钟同步), Date.getTime()也会被更新。 now()保证总是单调递增,所以它不受操作系统系统时间的影响 – 它总是挂钟时间(假设你的挂钟不是primefaces的)。

now()几乎可以用在每个new Date.getTime()+ new DateDate.now()都是的地方。 Datenow()时间是不能混合的,因为Date是基于unix-epoch (1970年以来的毫秒数),而now()是页面导航开始以来的毫秒数(所以它会比Date小得多)。

Chrome稳定版,Firefox 15 +和IE10均支持now() 。 也有几个polyfills可用。

现在有一种在javascript中测量微秒的新方法: http : //gent.ilcore.com/2012/06/better-timer-for-javascript.html

但是,在过去,我发现了一个粗略的方法,即在一个毫秒级的计时器中获得0.1毫秒的精度。 不可能? 不。 继续阅读:

我正在做一些高精度的实验,需要自检时间精度,并且发现在某些系统上,某些浏览器能够可靠地获得0.1毫秒的精度。

我发现,在快速系统上的现代GPU加速网页浏览器(例如i7四核,其中几个核心空闲,只有浏览器窗口) – 我现在可以相信定时器精确到毫秒级。 事实上,在闲置的i7系统上它变得非常精确,我已经能够可靠地获得相同的毫秒数,超过1000次的尝试。 只有当我试图做像加载额外的网页或其他的东西,毫秒的准确性降低(而且我能够成功地捕捉我自己降低的准确性,做一个前后的时间检查,看看是否我的处理时间突然加长到1毫秒或更长 – 这可以帮助我使可能受CPU波动影响太大的结果失效)。

它在i7四核系统上的一些GPU加速浏览器(当浏览器窗口是唯一的窗口)变得非常精确,我发现我希望能够在JavaScript中访问一个0.1ms的精度定时器,因为精度现在终于在一些高端的浏览系统上,使得这种定时器精度值得某些types的需要高精度的小众应用,并且应用程序能够自我validation精度偏差。

很显然,如果你做了几次,你可以简单地运行多次(如10次),然后除以10得到0.1毫秒的精度。 这是获得更好精度的常用方法 – 执行多次传球并按传球次数划分总时间。

但是,如果由于exception独特的情况,我只能做一个特定testing的单个基准testing,我发现我可以得到0.1(有时0.01毫秒)的精度:

初始化/校准:

  1. 运行一个繁忙的循环等待,直到计时器增加到下一个毫秒(alignment定时器到下一个毫秒间隔的开始)这个繁忙的循环持续less于一毫秒。
  2. 运行另一个繁忙循环来增加计数器,同时等待计时器递增。 计数器告诉你在一毫秒内发生了多less计数器增量。 这个繁忙的循环持续一整毫秒。
  3. 重复上述步骤,直到数字变得超稳定(加载时间,JIT编译器等)。 4. 注意 :数字的稳定性可以在空闲系统上达到您的精确度。 你可以计算方差,如果你需要自我检查的精度。 某些浏览器的差异较大,其他浏览器的差异较小。 在更快的系统上更大,更慢的系统上更慢。 一致性也不尽相同。 您可以知道哪些浏览器比其他浏览器更一致/更准确。 较慢的系统和繁忙的系统会导致初始化过程之间的较大差异。 如果浏览器没有给你足够的精度以允许0.1毫秒或0.01毫秒的测量,这可以给你显示警告消息的机会。 计时器歪斜可能是一个问题,但是某些系统上的某些整数毫秒计时器相当精确地递增(相当于点),这将导致您可以信任的非常一致的校准值。
  4. 保存最终的计数器值(或最后几次校准的平均值)

基准一次通过亚毫秒精度:

  1. 运行一个繁忙的循环等待,直到计时器增加到下一个毫秒(alignment定时器到下一个毫秒间隔的开始)。 这个繁忙的循环持续less于一毫秒。
  2. 执行您想要精确testing时间的任务。
  3. 检查计时器。 这给你整数毫秒。
  4. 运行最后一个繁忙循环来增加计数器,同时等待定时器增加。 这个繁忙的循环持续less于一毫秒。
  5. 将此计数器值除以初始化的原始计数器值。
  6. 现在你得到了毫秒的小数部分!!!!!!!!

警告:不build议在Web浏览器中使用繁忙循环,但幸运的是,这些繁忙的循环每次运行时间less于1毫秒,并且只运行几次。

JIT编译和CPU波动等variables增加了大量的错误,但是如果你运行了几个初始化过程,你将会完全dynamic的重新编译,最终计数器会很准确。 确保所有忙碌循环对于所有情况都是完全相同的function,以便繁忙循环中的差异不会导致差异。 在开始信任结果之前,确保所有代码行都执行了好几次,以使JIT编译器已经稳定到完全dynamic重新编译(dynarec)。

事实上,我在某些系统上看到精确度接近微秒,但是我还不能相信它。 但是0.1毫秒的精确度似乎在一个空闲的四核系统中非常可靠地工作,在这个空闲的四核系统中,我是唯一的浏览器页面。 我来到一个科学testing案例,我只能做一次性通过(由于独特的variables发生),并且需要精确地计时每次通过,而不是平均多次重复通过,所以这就是我为什么这样做的原因。

我做了几个预传和虚拟传球(也用于解决dynarec),以validation0.1ms精确度的可靠性(坚持几秒钟),然后把我的手放在键盘/鼠标上,而基准发生了,然后做了几个validation0.1ms精度的可靠性(再次保持稳定)。 这也validation了诸如电力状态变化之类的事情或者其他事情在事前和事后之间没有发生,干扰了结果。 在每个基准testing通过之间重复前测和后测。 在此之后,我几乎可以肯定,两者之间的结果是准确的。 当然,没有任何保证,但是它表明,在某些情况下,在Web浏览器中可以精确到<0.1ms精度。

这种方法只适用于非常小的情况。 即使如此,从字面上看也不会是100%无限的保证,当与内部和外部validation的几个层面相结合时,您可以获得相当可靠的准确性,甚至是科学的准确性。

总的来说,答案是“否”。 如果您在某些服务器端环境(即不在浏览器中)使用JavaScript,则所有投注都将closures,您可以尝试执行任何您想要的操作。

编辑 – 这个答案是旧的; 标准已经取得了进展,新的设施可以解决准确的时间问题。 即便如此,应该记住的是,在真正的实时操作系统之外,普通的非特权代码对其对计算资源的访问有限制。 测量性能与预测性能不一样(必然)。

下面是一个例子,显示了我的node.js的高分辨率定时器:

  function startTimer() { const time = process.hrtime(); return time; } function endTimer(time) { function roundTo(decimalPlaces, numberToRound) { return +(Math.round(numberToRound + `e+${decimalPlaces}`) + `e-${decimalPlaces}`); } const diff = process.hrtime(time); const NS_PER_SEC = 1e9; const result = (diff[0] * NS_PER_SEC + diff[1]); // Result in Nanoseconds const elapsed = result * 0.0000010; return roundTo(6, elapsed); // Result in milliseconds } 

用法:

  const start = startTimer(); console.log('test'); console.log(`Time since start: ${endTimer(start)} ms`); 

通常情况下,您可以使用:

  console.time('Time since start'); console.log('test'); console.timeEnd('Time since start'); 

如果您计算涉及循环的代码部分,则无法访问console.timeEnd()的值,以便将计时器结果添加到一起。 你可以,但它会变得讨厌,因为你必须注入你的迭代variables的值,比如i ,并设置一个条件来检测循环是否完成。

这是一个例子,因为它可能是有用的:

  const num = 10; console.time(`Time til ${num}`); for (let i = 0; i < num; i++) { console.log('test'); if ((i+1) === num) { console.timeEnd(`Time til ${num}`); } console.log('...additional steps'); } 

引用: https : //nodejs.org/api/process.html#process_process_hrtime_time