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

use*_*356 6 javascript event-loop settimeout node.js

假设我这样做:

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

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

clearTimeout(timer);
Run Code Online (Sandbox Code Playgroud)

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

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

Thi*_*ilo 5

Node.js 在单线程中执行。

所以不可能有任何竞争条件,你可以在它触发之前可靠地取消超时。

另请参阅相关讨论(在浏览器中)。

我说的是 setTimeout 时间实际到期并且解释器开始执行它的过程的情况

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

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


Sit*_*gui 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;
    // ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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

listOnTimeout

if (!first._onTimeout) continue;
Run Code Online (Sandbox Code Playgroud)