nodejs中的setInterval奇怪的行为

时间:2016-07-13 06:54:02

标签: javascript node.js setinterval

我想每秒运行一次函数,函数本身需要3秒才能执行。结果是每个区间的执行差异为<function execution time>*2+<setInterval delay>

我写了以下示例代码:

var seconds = 3;

setInterval(
    function(){
            console.info(new Date().toString());
            var waitTill = new Date(new Date().getTime() + seconds * 1000);
            while(waitTill > new Date()){}
    },1000
);

并且每次迭代都如我在公式中所述:

Wed Jul 13 2016 09:49:07 GMT+0300 (IDT)
Wed Jul 13 2016 09:49:14 GMT+0300 (IDT)
Wed Jul 13 2016 09:49:21 GMT+0300 (IDT)
Wed Jul 13 2016 09:49:28 GMT+0300 (IDT)

文档没有说明这种行为。我认为的结果是每次迭代将在1秒后执行,无论执行间隔函数需要多长时间。

发生了什么?

非常感谢有关该问题的任何信息。

谢谢!

使用Nodejs 6.3.0

更新

在浏览器上尝试了这个代码... google chrome ...这里的间隔每3秒执行一次,这仍然很奇怪。

更新

感谢您的所有评论,最后一件事情并不清楚。 为什么在NodeJS中,当我将setInterval()设置为1秒,并且函数执行需要3秒时,为什么下一次执行是7秒而不是4秒甚至3秒。这对我来说似乎很奇怪。这是一种可接受的行为吗?

1 个答案:

答案 0 :(得分:5)

  

文档未说明此行为

NodeJS的documentation for setInterval在特征上几乎没有说明它的行为,除了它将重复任务。

  

我认为的结果是每次迭代将在1秒后执行,无论执行间隔函数需要多长时间

如果你的意思是你可以有重叠的执行,你不能在NodeJS;它在一个线程上运行你的代码。

如果您的意思是您希望每次迭代在最后一次完成后运行一秒,那不是setInterval传统的工作方式。 setInterval传统上至少有两种不同的行为取决于您使用的实现:在当前的开始调度下一次迭代,或者在 end调度< / em>当前的一个。这只是在浏览器上。它来自been standardized for browsers,但NodeJS不是浏览器,不需要以相同的方式工作。 (事实上​​,它也不是另一种方式:在浏览器上,setInterval需要返回一个数字;在NodeJS上,它返回一个对象。)请记住,定时器不是JavaScript的一个特性,它们是是主机环境的一个特征。

相反,为了让它在之前完成后再次(大致)再次运行,请在函数末尾使用setTimeout来安排下一个运行一秒钟。

重新编辑:

  

为什么在NodeJS中,当我将setInterval()设置为1秒,并且函数执行需要3秒时,为什么下一次执行是7秒而不是4秒甚至3秒。这对我来说似乎很奇怪。这是一种可接受的行为吗?

是。这是奇怪和令人惊讶的(在我看来),但NodeJS确定了自己setInterval的行为,所以它是可接受的。在我的实验(下面)中,它似乎可以测量上一次执行函数所花费的时间,然后添加到计时器长度,以便在再次触发它之前它是lastExecutionLength + desiredInterval。这显然与浏览器规范不符,但同样,NodeJS不是浏览器。

这是我的测试脚本:

let counter = 0;
let timeAtEndOfLastExecution = 0;
let timer = null;

function log(msg) {
    console.log(Date.now() + ": " + msg);
}

function tick() {
    let start = Date.now();
    if (timeAtEndOfLastExecution) {
        log("tick (" + (Date.now() - timeAtEndOfLastExecution) + "ms)");
    } else {
        log("tick");
    }
    if (++counter == 10) {
        clearInterval(timer);
    } else {
        let wait = 200 + (Math.floor(8 * Math.random()) * 100);
        log("waiting " + wait + "ms");
        let stopWaiting = Date.now() + wait;
        while (Date.now() < stopWaiting) {
            // busy wait
        }
        log("exiting callback after " + (Date.now() - start) + "ms");
        timeAtEndOfLastExecution = Date.now();
    }
}
timer = setInterval(tick, 200);

运行示例(使用Node v6.2.2):

1468396730618: tick
1468396730619: waiting 400ms
1468396731020: exiting callback after 416ms
1468396731637: tick (617ms)
1468396731637: waiting 500ms
1468396732137: exiting callback after 500ms
1468396732837: tick (700ms)
1468396732837: waiting 900ms
1468396733737: exiting callback after 900ms
1468396734837: tick (1100ms)
1468396734837: waiting 300ms
1468396735137: exiting callback after 300ms
1468396735637: tick (500ms)
1468396735637: waiting 700ms
1468396736337: exiting callback after 700ms
1468396737237: tick (900ms)
1468396737237: waiting 800ms
1468396738037: exiting callback after 800ms
1468396739036: tick (999ms)
1468396739036: waiting 900ms
1468396739936: exiting callback after 900ms
1468396741036: tick (1100ms)
1468396741036: waiting 700ms
1468396741736: exiting callback after 700ms
1468396742636: tick (900ms)
1468396742636: waiting 200ms
1468396742836: exiting callback after 200ms
1468396743236: tick (400ms)

正如我们所看到的,它一直在等待上一次迭代的长度加上我给出的间隔:

  • 首次回调共计416毫秒;它返回后的下一个开始是617毫秒
  • 第二次回调耗时500ms;下一个在返回后的700ms开始
  • 第三次回调900ms;接下来在返回后的1100ms开始