哪一个首先触发setTimeout()创build或早些时候计划?

考虑以下..

var timeoutA = setTimeout(functionA, 200); // CPU intensive task blocks the event loop for ~50 ms var timeoutB = setTimeout(functionB, 100); // CPU intensive task blocks the event loop for ~200 ms // Now what? 

所以我们有一个情况,就是有两个超时的超时,两个超时都会在过去的某个时候开始。 其中一个(timeoutA)是自从创build第一个之后的两个中较早的一个,但另一个(timeoutB)计划尽快运行,即使它是第二个创build的。

哪个超时会先“赢”并执行其function? (特别是在node.js v5中,但也有兴趣听说其他引擎也)。

关于js定时器的执行顺序存在几个问题,但是没有解决创build顺序和定时执行顺序冲突的情况。 这些问题涉及定时器被创build和计划以相同顺序运行的实例:

  • 多个setTimeout()函数的执行顺序具有相同的时间间隔
  • 了解相继执行的setTimeout()函数

我理解asynchronous执行JS的方式如下。

有一个事件散列,其中包含所有事件中列出的asynchronous任务(例如设置超时,ajax请求,点击处理程序等)。 然后有一个队列,它包含所有“已触发”的事件(可以运行的callback,设置超时时间,单击已经听到的事件…)。 最后是一个运行循环,它通过做两件事来不断地pipe理这两个数据结构:首先,它重复检查事件散列中的事件是否需要放入队列中(比如setTimeout已经过去了,或者ajax请求已解决)。 其次,如果队列有一个需要调用的callback函数,则它将在队列中出队并调用下一个函数,每个循环一次。

现在进入你的问题的肉,事件以什么顺序进入这个队列?

基本上,当setTimeout被调用的时候,一个事件被添加到散列中,并带有一个特定的“时间签名”,也就是当前时间+传递给timeout参数的ms数量。 现在,当运行循环到达要将队列添加到队列中的位置时,如果看到多个setTimeouts准备好排队,它将首先排队具有较早“时间签名”的队列,然后排队另一个,以及任何其他准备就绪的事件(例如,如果在上述两个“时间签名”之间发生了事件callback将在两个setTimeouts之间发生的点击事件)。 所以,回到上面的例子,即使我们在你调用的这两个setTimeout函数的中间有一个cpu密集型任务,第二个setTimeout的'时间签名'+ 150ms小于第一个有+ 200毫秒,因此第二次调用setTimeout将在队列中的callback更高,它会被首先调用。

好的,在运行一些testing之后,似乎排定的顺序优先。 也就是说,在上面的例子中, timeoutB总是先执行。

 var scriptStart = Date.now(); // Create timeoutA console.log('Scheduling timeoutA for 200 ms in future'); var timeoutA = setTimeout(function () { console.log('Timeout A run after ' + (Date.now() - scriptStart) + ' ms'); }, 200); for (; (Date.now() - scriptStart) < 50;) { // Block the event loop for 50 ms }; console.log('Blocked till ' + (Date.now() - scriptStart) + ' ms'); // Create timeoutB console.log('Scheduling timeoutB for 100 ms in future'); var timeoutB = setTimeout(function () { console.log('Timeout B run after ' + (Date.now() - scriptStart) + ' ms'); }, 100); for (; (Date.now() - scriptStart) < 250;) { // Block the event loop for another 200 ms }; console.log('Blocked till ' + (Date.now() - scriptStart) + ' ms'); 

输出..

在将来调度timeoutA为200毫秒
阻塞到50毫秒
将来计划timeout为100毫秒
阻塞到250毫秒
超时B在250 ms后运行
超时250 ms后运行

这对于所有已经出现的js引擎都是适用的,具体来说:

  • node.js(v0.12.4,v4.1.1,v5.0.0)
  • iojs(v1.8.1,v2.0.2,v3.0.0)
  • Sarafi(v9.0.2)
  • Chrome(v47.0.2526)