让我说我这样做:
var timer = setTimeout(function() {
console.log("will this happen?");
}, 5000);
然后在不到5秒钟后,另一个回调(例如来自NodeJS中的网络事件)触发并清除它:
clearTimeout(timer);
是否有可能来自setTimeout调用的回调已经在此时执行的队列中,如果是这样,clearTimeout是否及时停止它?
为了澄清,我说的是setTimeout时间实际到期并且解释器启动执行它的过程的情况,但是另一个回调当前正在运行,因此消息被添加到队列中。看起来这些竞争条件类型之一很容易不被考虑。
答案 0 :(得分:5)
即使Node是单线程,问题描述的竞争条件也是可能的。
可能会发生这种情况,因为定时器是由本机代码(在lib_uv中)触发的。 最重要的是,Node将具有相同超时值的计时器分组。因此,如果您在同一个ms内安排两个具有相同超时的计时器,它们将立即添加到事件队列中。
但是放心的节点在内部解决了这个问题。从节点0.12.0引用代码:
exports.clearTimeout = function(timer) {
if (timer && (timer[kOnTimeout] || timer._onTimeout)) {
timer[kOnTimeout] = timer._onTimeout = null;
// ...
}
}
在清除超时时,Node会在内部删除对回调函数的引用。因此,即使竞争条件发生,它也不会造成伤害,因为这些计时器将被跳过:
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事件循环构建的不同内部实现。