Javascript内部 - 在它发生之前的clearTimeout

时间:2014-06-10 09:47:01

标签: javascript node.js settimeout event-loop

让我说我这样做:

var timer = setTimeout(function() {
    console.log("will this happen?");
}, 5000);

然后在不到5秒钟后,另一个回调(例如来自NodeJS中的网络事件)触发并清除它:

clearTimeout(timer);

是否有可能来自setTimeout调用的回调已经在此时执行的队列中,如果是这样,clearTimeout是否及时停止它?

为了澄清,我说的是setTimeout时间实际到期并且解释器启动执行它的过程的情况,但是另一个回调当前正在运行,因此消息被添加到队列中。看起来这些竞争条件类型之一很容易不被考虑。

3 个答案:

答案 0 :(得分:5)

即使Node是单线程,问题描述的竞争条件也是可能的。

可能会发生这种情况,因为定时器是由本机代码(在lib_uv中)触发的。 最重要的是,Node将具有相同超时值的计时器分组。因此,如果您在同一个ms内安排两个具有相同超时的计时器,它们将立即添加到事件队列中。

但是放心的节点在内部解决了这个问题。从节点0.12.0引用代码:

timer.js > clearTimeout

exports.clearTimeout = function(timer) {
  if (timer && (timer[kOnTimeout] || timer._onTimeout)) {
    timer[kOnTimeout] = timer._onTimeout = null;
    // ...
  }
}

在清除超时时,Node会在内部删除对回调函数的引用。因此,即使竞争条件发生,它也不会造成伤害,因为这些计时器将被跳过:

listOnTimeout

if (!first._onTimeout) continue;

答案 1 :(得分:4)

Node.js在单个线程中执行。

因此不存在任何竞争条件,您可以在触发之前可靠地取消超时。

另见a related discussion (in browsers).

  

我说的是setTimeout时间实际到期且解释器启动执行过程的情况

没有看过Node.js的内部结构,我认为这是不可能的。一切都是单线程的,因此在代码运行时,解释器不能“在进行中”做任何事情。

您的代码必须在触发超时之前返回控制权。如果在代码中放置一个无限循环,整个系统就会挂起。这都是“合作多任务处理”。

答案 2 :(得分:0)

此行为在HTML标准中为defined,激发的任务开始于:

  

如果已清除活动计时器列表中的句柄条目,则中止这些步骤。

因此,即使任务已经排队,它也会被中止。

但是,这是否适用于Node.js还是有争议的,因为the documentation只是指出:

  

Node.js中的计时器函数实现了与Web浏览器提供的计时器API类似的API,但是使用了围绕Node.js事件循环构建的不同内部实现。