setTimeout在长时间运行的函数中引入延迟

时间:2015-12-10 12:23:45

标签: node.js

下面的代码执行一个长时间运行的函数(一个睡眠以保持简单),然后使用setTimeout再次回调自身。我正在使用nodejs 5.1.0

var start_time = Math.ceil(new Date() /1000)
function sleep(delay) {
  var start = new Date().getTime();
  while (new Date().getTime() < start + delay);
}

function iteration(){
  console.log("sleeping at :", Math.ceil(new Date()/1000 - start_time));
  sleep(10000); // sleep 10 secs
  console.log("waking up at:", Math.ceil(new Date()/1000 - start_time));
  setTimeout(iteration, 0); 
}

iteration();

在调用setTimeout的那一刻节点没有做任何事情(理论上事件循环为空?)所以我希望立即执行回调。换句话说,我希望程序在唤醒后立即进入睡眠状态。

然而,这是发生的事情:

>iteration();
sleeping at : 0
waking up at: 10
undefined
> sleeping at : 10 //Expected: Slept immediately after waking up
waking up at: 20
sleeping at : 30 //Not expected: Slept 10 secs after waking up
waking up at: 40
sleeping at : 50 //Not expected: Slept 10 secs after waking up
waking up at: 60
sleeping at : 70 //Not expected. Slept 10 secs after waking up
waking up at: 80
sleeping at : 90 //Not expected: Slept 10 secs after waking up
waking up at: 100
sleeping at : 110 //Not expected: Slept 10 secs after waking up

正如您所看到的,程序在第一次唤醒后立即睡眠(这是我所期望的),但之后却没有。事实上,它在醒来和睡觉之间等待了10秒。

如果我使用setImmediate,一切正常。知道我错过了什么吗?

编辑:

注意:

1-在我的实际代码中,我有一个复杂的长算法而不是一个简单的睡眠函数。上面的代码只是在一个更简单的用例中重现了这个问题。 这意味着我无法使用setTimeout(iteraton,10000)

2-我使用延迟为0的setTimeout的原因是因为我的代码阻塞了nodejs很长时间以至于其他较小的任务被延迟了。通过执行setTimeout,nodejs返回事件循环以执行那些小任务,然后继续处理我的主要长期运行代码

3-我完全理解setInterval(function,0)将尽快运行,而不是立即运行,但这并不能解释为什么它运行10秒延迟,因为nodejs没有做任何其他事情

4- Chrome中的代码运行没有任何问题。 Nodejs bug?

1 个答案:

答案 0 :(得分:0)

首先看一下node.js documenation

  

请务必注意,您的回调可能不会被调用   在完全延迟毫秒 - Node.js不保证   回调将触发的确切时间,也不是排序   事情会发生。回调将尽可能接近   到指定的时间。

为了使你的功能更加异步,你可以做出类似的事情:

function iteration(callback){
  console.log("sleeping at :", Math.ceil(new Date()/1000));
  sleep(10000); // sleep 10 secs
  console.log("waking up at:", Math.ceil(new Date()/1000));
  return setTimeout(callback(iteration), 0);      
}

iteration(iteration);

下一个问题是你的睡眠功能。你有一个while循环阻塞你所有的node.js进程,以便为你创建node.js的setTimeout函数。

function sleep(delay) {
  var start = new Date().getTime();
  while (new Date().getTime() < start + delay);
}

现在发生的事情是你的睡眠功能正在阻止这个过程。当你在setTimeout的异步调用之后,通过node.js初始化函数的范围时,不仅在你直接调用函数时也会发生这种情况。

这不是一个错误。它必须是这样的,因为在你的while循环内部可能是你的迭代函数必须知道的东西。特别是在setTimeout之后调用它。因此,首先检查睡眠功能,并尽快调用该函数。

问题更改后编辑的答案