JavaScript是否提供高分辨率计时器?

JavaScript是否提供高分辨率计时器?

我从零开始写了几个游戏引擎,一些用C语言编写,一些用Java用,一些用Flash。 当谈到animation和交互式graphics时,我总是遵循相同的基本模型。 用下面的devise创build一个基本的类/结构:

void init() { /* Called once, preload essential resources here. */ } void update(double time) { /* Updates game/animation state using high resolution time. */ } void render(double time) { /* Updates screen graphics using high resolution time. */ } void run() { double time; init(); while (!done) { time = queryTime(); update(time); render(time); } } 

时间对平滑animation和游戏状态计算非常重要。 在本地代码Windows中,我使用QueryPerformanceCounter()QueryPerformanceFrequency() queryTime()在每个游戏循环中执行queryTime()angular色,并传递时间来更新/呈现。 在Java中,我使用System.nanoTime()

JavaScript中的等价物是什么? 也就是说,一些像queryTime()这样的函数返回一个精确度很高的时间值(亚毫秒)。 从我听说最好的准确性,你可以在JavaScript中获得约15毫秒…这是animation可怕的。

请参阅下面的@ h3r3的答案。 这是正确的答案。

毫秒是你可以在JavaScript中所期望的最好的。 而且,就像你说的那样,这不是很准确。 请参阅堆栈溢出问题JavaScript中的微秒计时

timer.js旨在提供最高达微秒的分辨率,但仅适用于Google Chrome 。

更新 :timer.js不支持微秒的分辨率。 它只是将毫秒数乘以1000。

对不起,没有更好的消息!

几乎所有的现代浏览器都提供高分辨率定时器。 这是“高分辨率时间”W3C标准: http : //www.w3.org/TR/hr-time/#sec-DOMHighResTimeStamp 。

它允许您通过调用window.performance.now()来获得一个亚毫秒精度的时间戳。 这将返回一个以毫秒为单位的时间戳,但它是一个浮点数,因此您仍然可以获得亚毫秒的分辨率。

很老的浏览器可能会实现这个标准的“前缀”版本,例如用于实现window.performance.webkitNow()的基于WebKit的浏览器。

这里有一些代码可以用来得到准确的时间戳,如果可用的话还原到标准精度,否则:

 if (window.performance.now) { console.log("Using high performance timer"); getTimestamp = function() { return window.performance.now(); }; } else { if (window.performance.webkitNow) { console.log("Using webkit high performance timer"); getTimestamp = function() { return window.performance.webkitNow(); }; } else { console.log("Using low performance timer"); getTimestamp = function() { return new Date().getTime(); }; } } getTimestamp(); 

请注意,此getTimestamp()函数不会返回表示当前date/时间的值。 返回的值只能用于测量时间段,通过减去两个不同的时间戳。 例如

 var t1 = getTimestamp(); //... some other code var t2 = getTimestamp(); console.log("Time delta: " + (t2 - t1)); 

而不是while (true) / setInterval ,使用recursion的requestAnimationFrame 。 它会比基于超时的animation更平滑。 它提供时间戳,如果你需要你的animation运行在较慢的path。

截至目前(2013年2月25日),Chrome 24中的高性能时代的质量非常糟糕。

 var old = 0; for (var i=0; i<10; i++) { var t = window.performance.now(); var d = t - old; old = t; console.log(t + ' += ' +d); } 

输出这样的东西:

 609689.000000013 += 609689.000000013 609689.9999999441 += 0.9999999310821295 609689.9999999441 += 0 609689.9999999441 += 0 609689.9999999441 += 0 609690.9999999916 += 1.0000000474974513 609690.9999999916 += 0 609690.9999999916 += 0 609691.9999999227 += 0.9999999310821295 609691.9999999227 += 0 

这说明了

1)抽样发生很less

2)精度仍然在1ms左右,不在微秒范围内。

Node.js也有一个高分辨率的定时器。

 process.hrtime() 

详细信息请参阅文档

这里是你的代码应该在JavaScript中看起来像,所以它不会阻止用户界面,并不使用window.requestAnimationFrame不能跨浏览器。

 /* Called once, preload essential resources here. */ function init() {} /* Updates game/animation state */ function update(time) {} /* Updates screen graphics */ function render(time) {} window.onload = function() { var time; var done = false; init(); // Using setTimeout passing zero makes the animate function run // as soon as possible, but yielding first. setTimeout(animate, 0); function animate () { time = new Date(); update(time); render(time); if (!done) { setTimeout(animate, 0); } } } 

这种方法的一个问题是animate()可能比屏幕更新更频繁(在60Hz下不会更新,而不是每16ms更新一次),从而导致额外的渲染永远不会显示在屏幕上。 这就是为什么你应该坚持使用requestAnimationFrame。

因为在searchJavaScript和高分辨率定时器时出现这个问题,所以值得注意的是window.performance.now现在可以正常工作(至less在Google Chrome v.26中)并且提供〜微秒的分辨率。

 var d = 0; var p = window.performance; for(var i=0; i<10; i++) { d = -1 * (p.now() - p.now()); console.log(d*1000); } 

它给了我(微秒):

 5.0000089686363935 3.9999722503125668 1.00000761449337 1.00000761449337 1.00000761449337 1.9999861251562834 1.9999861251562834 1.00000761449337 1.00000761449337 0.9999785106629133 

我在几组10k +结果上跑了一些数据。 最小值约为1微秒,我的机器( MacBook Air )的平均值约为1.25微秒。 有时候在100微秒以上的时候有很高的exception值,但是在10微秒以上频繁出现结果。

所以高分辨率定时器现在能够以微秒的分辨率进行定时减法。

您可以使用CSS 3变换来获得完整的硬件加速,并且可以在大多数现代浏览器上运行stream畅的animation效果。如果您期望WebGL上的animation效果非常stream畅,那么您的操作就不那么幸运了,因为没有亚毫秒级的精度在JavaScript上。

目前,在networking上启用游戏相关技术方面还有很多进展(例如,请参阅我们的全屏API正在积极开发的鼠标locking草案…也许您可以在JavaScript中启动微秒精度定时器的运动;-)

除了已经提供的优秀答案,你也可以看看marky ,a

基于性能的高分辨率JavaScript定时器。标记/测量(461字节分钟+ gz)

它还包括开发工具可视化,并在广泛的浏览器中进行testing。