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

Javascript Node.js setInterval和nextTick对于第二次调用不准确,javascript,node.js,timer,Javascript,Node.js,Timer,首先,我要说,我完全知道JS中的计时器不准确。这不是重点。我对以下行为的原因感兴趣更多是出于好奇 我通过setInterval或setTimeout计划每x ms运行一个函数。我还以ms的精度测量实际经过的时间。代码如下: var counter = 0; var start = Date.now(); var last = start; var now; var step = 10; var tick = function () { now = Date.now(); con

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

我通过
setInterval
setTimeout
计划每x ms运行一个函数。我还以ms的精度测量实际经过的时间。代码如下:

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毫秒

延迟100 ms的相同实验:

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
第二条线再次突出

使用
过程可以生成更精确的版本。nextTick

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);
现在,除了第二次通话外,所有通话都很完美


有人能解释为什么吗?我想这是必须在系统级处理的事情。

这是因为
控制台.log()
。由于
console.log
在第一次调用期间占用更多的cpu时间,因此第二个操作将花费更长的时间。(警告:这是一个有根据的猜测)

结果:

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);

我的第一个猜测是,在以常规模式运行之前,节点必须执行一些启动工作。比如说,你试过在1秒钟的热身后运行你的代码吗?
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
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);
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