javascript - Node.js setInterval 和 nextTick 第二次调用不准确

标签 javascript node.js timer

首先我要说的是,我完全意识到 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 毫秒的偏差。

延迟 100 毫秒的相同实验:

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构建更准确的版本:

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

关于javascript - Node.js setInterval 和 nextTick 第二次调用不准确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32620453/

相关文章:

sql-server - 使用node js和mssql插入请求参数

c# - Tulpep PopupNotifier 无法与计时器一起使用

javascript - 暂停/恢复在nodejs中执行的代码

javascript - 我的 ng-view DIV 消失 - Angular JS 1.x

javascript - 如何在我的列表组元素中对齐我的列表以打印漂亮

javascript - 工具提示最大宽度设置

javascript - 如何使用 sinon.js stub 链接函数

mysql - Sequelize 映射不能使用 max 和 col

具有事件计时器 (setTimeout) 的 Node.js 可扩展性

javascript - 如何阻止 mousedown 事件在外部元素中触发?