JavaScript中是否有具有微秒级分辨率的计时功能?
我知道适用于Chrome 的timer.js,希望能够为其他友好的浏览器提供解决方案,例如Firefox,Safari,Opera,Epiphany,Konqueror等。我对支持任何IE均不感兴趣,但可以提供包括 IE 在内的答案受欢迎的。
(鉴于JS中毫秒级计时的准确性很差,因此我不屏住呼吸!)
更新:timer.js宣传微秒分辨率,但仅将毫秒读数乘以1,000。通过测试和代码检查验证。失望了 :[
JavaScript中是否有具有微秒级分辨率的计时功能?
我知道适用于Chrome 的timer.js,希望能够为其他友好的浏览器提供解决方案,例如Firefox,Safari,Opera,Epiphany,Konqueror等。我对支持任何IE均不感兴趣,但可以提供包括 IE 在内的答案受欢迎的。
(鉴于JS中毫秒级计时的准确性很差,因此我不屏住呼吸!)
更新:timer.js宣传微秒分辨率,但仅将毫秒读数乘以1,000。通过测试和代码检查验证。失望了 :[
Answers:
正如Mark Rejhon的答案所暗示的那样,现代浏览器中有一个API可以将亚毫秒级分辨率的计时数据公开给脚本:W3C High Resolution Timer,又名window.performance.now()。
now()Date.getTime()在两个重要方面优于传统:
now()是具有毫秒级分辨率的双精度型,表示自页面导航开始以来的毫秒数。它以分数形式返回微秒数(例如,值1000.123为1秒和123微秒)。
now()在单调增加。因为这是重要的Date.getTime()可可能是跳跃式前进或后退,甚至在随后的调用。值得注意的是,如果OS的系统时间已更新(例如原子时钟同步),Date.getTime()则也会更新。 now()保证总是单调增加,因此它不受操作系统的系统时间的影响-始终是挂钟时间(假设挂钟不是原子钟...)。
now()可几乎每一个地方,用在new Date.getTime(),+ new Date和Date.now()是。唯一的例外是,Date与now()时代不混合,如Date基于UNIX的时期(自1970年以来的毫秒数),而now()就是因为你的页面的导航启动(所以它会远小于毫秒数Date)。
now()在Chrome稳定版,Firefox 15+和IE10中受支持。也有几种填充料。
new Date.getTime()不是什么 new Date().getTime()是。
console.log每次运行都做起来像昂贵的事情,我在一台好的机器上都会发生10%的碰撞)很难找出来,但是在这里复制所有突出显示的代码:last=-11; same=0; runs=100; for(let i=0;i<runs;i++) { let now = performance.now(); console.log('.'); if (now === last) { same++; } last = now; } console.log(same, 'were the same');
现在有了一种新的测量javascript中微秒的方法:http : //gent.ilcore.com/2012/06/better-timer-for-javascript.html
但是,在过去,我发现了一种粗略的方法,可以从毫秒计时器中获得JavaScript的0.1毫秒精度。不可能?不。继续阅读:
我进行了一些高精度的实验,需要对计时器的准确性进行自我检查,发现使用某些系统上的某些浏览器,我能够可靠地获得0.1毫秒的精度。
我发现在快速系统(例如,i7四核,其中几个核处于空闲状态,只有浏览器窗口)上的现代GPU加速的Web浏览器中-我现在可以相信计时器的精度是毫秒。实际上,在闲置的i7系统上,它变得如此精确,我已经能够可靠地获得完全相同的毫秒数,超过1000次尝试。仅当我尝试执行诸如加载额外网页或其他操作之类的操作时,毫秒级的精度才会降低(而且我可以通过前后的时间检查来成功地发现自己降低的精度,以查看是否我的处理时间突然延长到1或更多毫秒-这可以帮助我使可能受到CPU波动不利影响的结果无效)。
在i7四核系统上的某些GPU加速浏览器中(当浏览器窗口是唯一窗口时),它变得如此精确,以至于我希望我可以在JavaScript中访问一个0.1ms的精度计时器,因为精度现在终于可以了在某些高端浏览系统上,这些计时器精度对于某些类型的需要高精度的小众应用程序值得,并且这些应用程序能够针对精度偏差进行自我验证。
显然,如果您要进行多次扫描,则可以简单地运行多次扫描(例如10次扫描),然后除以10以得到0.1毫秒的精度。这是提高精度的常用方法-进行多次遍历,然后将总时间除以遍历次数。
但是...如果由于异常特殊的情况我只能对特定测试进行一次基准测试合格,我发现通过执行以下操作可以得到0.1(有时是0.01ms)的精度:
初始化/校准:
将一次传递基准化为亚毫秒精度:
警告:不建议在Web浏览器中使用忙循环,但是幸运的是,这些忙循环每次运行的时间都少于1毫秒,并且只能运行几次。
诸如JIT编译和CPU波动之类的变量会增加大量的不准确性,但是如果您运行几次初始化遍历,则将具有完全的动态重新编译,最终计数器会稳定到非常准确的水平。确保所有情况下所有繁忙循环的功能都完全相同,以便繁忙循环中的差异不会导致差异。在开始信任结果之前,请确保多次执行所有代码行,以使JIT编译器已经稳定到完全动态重新编译(dynarec)的程度。
实际上,我在某些系统上目睹了接近微秒的精度,但是我还不相信它。但是,在闲置的四核系统(我是唯一的浏览器页面)上,0.1毫秒的精度似乎相当可靠。我来到一个科学测试用例中,我只能进行一次通过(由于出现了唯一变量),并且需要精确地确定每次通过的时间,而不是平均多次重复通过,所以这就是我这样做的原因。
我进行了几次预传和伪传(也用于解决dynarec的问题),以验证0.1ms精度的可靠性(保持稳定状态几秒钟),然后将手放在键盘/鼠标上,而没有出现基准测试,然后进行了几次通过后验证0.1ms精度的可靠性(再次保持稳定)。这也可以验证在前后之间没有发生诸如电源状态更改或其他内容之类的事情,从而干扰结果。在每个基准测试通过之间重复前测和后测。基于此,我几乎可以肯定两者之间的结果是准确的。当然,我们不能保证,但是这表明在某些情况下,Web浏览器可以达到<0.1ms的精确度。
此方法仅在非常非常特殊的情况下有用。即使如此,从字面上看,它也不是100%无限保证的,与多层内部和外部验证结合使用时,您可以获得非常值得信赖的准确性,甚至科学准确性。
Date.now()或+new Date()。但是现在我们有了performance.now()。很显然,您已经找到了一些破解更多功能的好方法,但是这个答案实际上已经过时了。另外,请勿推荐与忙碌循环相关的任何内容。只是不要那样做。我们不需要更多。
这是一个示例,显示了我的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()以便将计时器结果加在一起。可以,但是会变得很讨厌,因为您必须注入迭代变量的值,例如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