JavaScript中的高精度计时

HRT(High Resolution Timing, 高精度计时)在一些场合有很大的作用,比如游戏开发中,需要精确的计算两帧之间的时间差。


在JS中常常用(new Date()).getTime()来获取毫秒级的时间戳,虽然是毫秒级,但事实上它的真实精度只能达到大概16ms的级别。例如


while (true){

console.log((new Date()).getTime()); // 这样死循环浏览器会跪的,责任自负

}


会发现它事实上大概16ms才跳一次,也许是17ms、又或者15ms吧,反正实际精度是有限的——什么?你跟我说是1ms?我告诉你那是因为新的系统或者浏览器使用了更高精度——但这不影响这篇文章的内容……


这对于日常应用来说完全够用了,但是对于游戏这样的场合,高精度计时就有它不可取代的意义了。


故事从这里开始


上面的获得毫秒级时间戳的方式之所以精度有限,是因为它的实现方式,以及它“绝对时间”的定义。


以Windows为例,这一类时间戳所使用的系统调用,比如GetSystemTime()MSDN、GetTickCount()MSDN,其函数的取值并不是实时的,而是通过硬件的时钟中断被动刷新的,这里的刷新间隔“正好”就是上面那个16ms。以GetSystemTime()为例,它返回的是SYSTEMTIME结构体,这用来进行时间日期处理的,因为时间日期处理通常根本不需要也不应该用那么高的精度(甚至很多时候只需要秒级别的精度),所以(new Date()).getTime()通过它们实现的确是可以胜任的。


现在我们明白了,靠这个时间戳是不能实现高精度计时的。


在Windows上,常常有两种高精度计时的方式:


第一种是timeGetTime()MSDN,它能返回系统启动到现在所经过的毫秒数,精度是1ms,因为它是32位的,所以大概49.71天会溢出清零。

第二种QueryPerformanceCounter()配合QueryPerformanceFrequency()MSDN实现,能够实现微秒级别的计时精度,对于大多数场合而言都够了。


当然还有更先进的方法,是通过CPU中的硬件计数器,和CPU每个时钟周期的时间,计算出更精确的时间(通常是纳秒级别的),对精度要求极高的场合这是最精确的选择了。


通常在使用固定位数的情况下,精度越高意味着计时的范围越小,这就不罗嗦了。


回到JavaScript中来


上面那些乱七八糟系统调用其实更咱们都没什么太大关系,我们能干什么完全看运行环境乐意给什么。


在webkit中提供了performance.now()参考文献来获取一个毫秒级的浮点数时间戳,我没查到资料它的有效精度是多少,不过既然给了个浮点数那就这么用着吧,我们就当它是微秒级的了!


在node.js中,有process.hrtime()DOC,返回的是一个数组[seconds, nanoseconds],看起来它具有纳秒级别的精度?且信了吧。


综合一下,我写了下面的代码


exports.time = (function(){

if (typeof window !== 'undefined'){

// 浏览器

if (typeof window.performance !== 'undefined' && typeof performance.now !== 'undefined'){

// support hrt

return function(){

return performance.now();

};

}else{

// oh no..

return function(){

return (new Date()).getTime();

};

}

}else{

// node.js

return function(){

var diff = process.hrtime();

return (diff[0] * 1e9 + diff[1]) / 1e6; // nano second -> ms

};

}

})();


有了上面的代码(gist),我们就能写一个秒表神马的,在做性能测试的时候就用得上了。


最后还是要唠叨一句,HRT是用来计算时间差的,不是用来计算现实中时间(挂钟时间)的。


下一篇文章中,将会对JS中的时间精度进行进一步的讨论,对象自然就是setTimeout/setInterval了!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值