Javascript内部-在触发之前clearTimeout

Javascript内部-在触发之前clearTimeout,javascript,node.js,settimeout,event-loop,Javascript,Node.js,Settimeout,Event Loop,假设我这样做: var timer = setTimeout(function() { console.log("will this happen?"); }, 5000); 然后在不到5秒钟后,另一个回调(例如来自NodeJS中的网络事件)将触发并清除它: clearTimeout(timer); 是否有可能来自setTimeout调用的回调已经在此时要执行的队列中,如果是,clearTimeout会及时停止它吗 为了澄清这一点,我讨论的是一种情况,即setTimeout时间实际过

假设我这样做:

var timer = setTimeout(function() {
    console.log("will this happen?");
}, 5000);
然后在不到5秒钟后,另一个回调(例如来自NodeJS中的网络事件)将触发并清除它:

clearTimeout(timer);
是否有可能来自setTimeout调用的回调已经在此时要执行的队列中,如果是,clearTimeout会及时停止它吗


为了澄清这一点,我讨论的是一种情况,即setTimeout时间实际过期,解释器开始执行它,但另一个回调当前正在运行,因此消息被添加到队列中。这似乎是一种很容易忽略的竞争条件类型。

Node.js在单个线程中执行

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

另见

我说的是一种情况,setTimeout时间实际上过期了,解释器开始执行它

如果没有查看Node.js内部,我认为这是不可能的。一切都是单线程的,因此在代码运行时,解释器不能“处于”执行任何操作的过程中


您的代码必须返回控制才能触发超时。如果在代码中放入无限循环,整个系统将挂起。这都是“协作多任务处理”。

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

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

但放心节点可以在内部为您解决这一问题。引用节点0.12.0中的代码:

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

此行为在HTML标准中,激发的任务以以下内容开始:

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

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

然而,这是否适用于Node.js仍有争议,正如所述:

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


我认为说
Node.js在单个线程中执行是不合适的。因此,不存在任何竞争条件
。要得到一个好的解释,请参阅此评论,这可能会导致对“竞争条件”定义的讨论
exports.clearTimeout = function(timer) {
  if (timer && (timer[kOnTimeout] || timer._onTimeout)) {
    timer[kOnTimeout] = timer._onTimeout = null;
    // ...
  }
}
if (!first._onTimeout) continue;