node.js中的setInterval怪异行为

ufk*_*ufk 3 javascript setinterval node.js

我想每秒运行一次函数,而函数本身需要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
);
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

文档没有说明此行为。我认为的结果是,无论间隔函数的执行花费多少时间,每次迭代都会在1秒后执行。

这是怎么回事?

任何有关此问题的信息将不胜感激。

谢谢!

使用Nodejs 6.3.0

更新

在浏览器上尝试过此代码...谷歌浏览器...在这里,间隔每3秒执行一次,仍然很奇怪。

更新

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

T.J*_*der 5

文档没有说明此行为

NodeJS的特征文档setInterval几乎没有说明其行为,只是重复了任务。

我认为的结果是,无论间隔函数的执行花费多少时间,每次迭代都会在1秒后执行

如果您的意思是执行可能重叠,则不能使用NodeJS。它在单个线程上运行您的代码。

如果您希望每次迭代都在最后一次完成之后运行一秒钟,那么这不是setInterval传统上的工作方式。setInterval传统上,根据所使用的实现,它至少具有两种不同的行为:在当前迭代的开始处调度下一个迭代,或在当前迭代的末尾调度下一个迭代。那只是在浏览器上。从那时起,它已针对浏览器进行了标准化,但是NodeJS不是浏览器,并且不需要以相同的方式工作。(实际上,它也没有其他方式:在浏览器上,setInterval要求返回一个数字;在NodeJS上,它返回一个对象。)请记住,计时器不是JavaScript的功能,而是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);
Run Code Online (Sandbox Code Playgroud)

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

1468396730618:勾号
1468396730619:等待400毫秒
1468396731020:416毫秒后退出回调
1468396731637:勾号(617ms)
1468396731637:等待500ms
1468396732137:500毫秒后退出回调
1468396732837:勾号(700ms)
1468396732837:等待900ms
1468396733737:900毫秒后退出回调
1468396734837:勾号(1100ms)
1468396734837:等待300毫秒
1468396735137:300毫秒后退出回调
1468396735637:勾号(500ms)
1468396735637:等待700ms
1468396736337:700毫秒后退出回调
1468396737237:勾号(900ms)
1468396737237:等待800毫秒
1468396738037:在800毫秒后退出回调
1468396739036:勾号(999ms)
1468396739036:等待900ms
1468396739936:900毫秒后退出回调
1468396741036:勾号(1100ms)
1468396741036:等待700ms
1468396741736:700毫秒后退出回调
1468396742636:勾号(900ms)
1468396742636:等待200毫秒
1468396742836:200毫秒后退出回调
1468396743236:勾号(400ms)

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

  • 第一次回调总共耗时416毫秒;下一次开始返回后617ms
  • 第二次回调耗时500毫秒;下一次返回后700毫秒开始
  • 第三回叫900ms; 下一次在返回后1100毫秒开始