对于第二次调用,Node.js setInterval和nextTick不准确

让我先说这个,说我完全知道JS中的计时器是不准确的 。 这不是重点。 我对以下行为更感兴趣的原因是好奇心。

我正在调度一个函数通过setIntervalsetTimeout运行每x毫秒。 我也测量了一个毫秒准确度的实际时间。 这是代码:

 var counter = 0; var start = Date.now(); var last = start; var now; var step = 10; var tick = function () { now = Date.now(); console.log(counter++, now, now - last); last = now; if (counter > 10) { clearInterval(tick); } }; setInterval(tick, step); 

Ubuntu 15.04(3.19.0-15-generic)上的Node.js 4.0.0的输出如下:

 0 1442445968559 11 1 1442445968597 38 2 1442445968611 14 3 1442445968621 10 4 1442445968632 11 5 1442445968641 9 6 1442445968651 10 7 1442445968661 10 8 1442445968672 11 9 1442445968683 11 

我可以看到大多数呼叫的1到2毫秒的不准确性。 有趣的是第二行是28毫秒。

延迟100ms的同样的实验:

 0 1442446176790 100 1 1442446176940 150 2 1442446177044 104 3 1442446177145 101 4 1442446177245 100 5 1442446177345 100 6 1442446177446 101 7 1442446177546 100 8 1442446177646 100 9 1442446177747 101 

再次,第二条线突出。

使用process.nextTick可以build立更准确的版本:

 var counter = 0; var start = Date.now(); var last = start; var now; var step = 10; var check = function () { now = Date.now(); if (now >= last + step) { tick(); } if (counter < 10) { process.nextTick(check); } }; var tick = function () { console.log(counter++, now, now - last); last = now; }; process.nextTick(check); 

结果是:

 0 1442446399599 10 1 1442446399620 21 2 1442446399630 10 3 1442446399640 10 4 1442446399650 10 5 1442446399660 10 6 1442446399670 10 7 1442446399680 10 8 1442446399690 10 9 1442446399700 10 

现在除了第二个电话都是完美的。

有人可以解释为什么吗? 我想这是必须在系统层面上处理的。

这是因为console.log() 。 由于console.log在第一次调用期间需要更多的CPU时间,所以第二个操作将花费更长的时间。 (警告:这是一个有教养的猜测)

 var counter = 0; var start = Date.now(); var last = start; var now; var step = 10; var data = []; var tick = function () { now = Date.now(); var time = now - last; last = now; counter++; data.push(counter + " " + now +" "+time); if (counter > 10) { clearInterval(interval); console.log(data.join('\n')); } }; var interval = setInterval(tick, step); 

结果:

 1 1442450286606 12 2 1442450286617 11 3 1442450286627 10 4 1442450286637 10 5 1442450286648 11 6 1442450286658 10 7 1442450286668 10 8 1442450286678 10 9 1442450286688 10 10 1442450286698 10 11 1442450286708 10 

编辑 – 上述与CPU处理的修改给我的假设一点额外的权重。

 var counter = 0; var start = Date.now(); var last = start; var now; var step = 10; var data = []; var tick = function () { now = Date.now(); var time = now - last; last = now; counter++; data.push(counter + " " + now +" "+time); if (counter == 4){ for (var i=0;i<10000000;i++){ //waste some time } } if (counter > 10) { clearInterval(interval); console.log(data.join('\n')); } }; var interval = setInterval(tick, step); 

结果显示cpu更繁忙后时间增加:

 1 1442451041828 12 2 1442451041838 10 3 1442451041849 11 4 1442451041860 11 5 1442451041902 42 6 1442451041914 12 7 1442451041924 10 8 1442451041934 10 9 1442451041944 10 10 1442451041954 10 11 1442451041964 10