Javascript事件队列是否是一个简单的FIFO?

时间:2016-02-09 16:16:54

标签: javascript settimeout

看一下这个例子:

function A() { console.log('A'); }
function B() { console.log('B'); }
// and then i setTimeout(fn, 0) both of them
setTimeout(A, 0);
setTimeout(B, 0);

是否保证B会在A之后立即运行? 浏览器是否可能在AB之间的队列中添加另一个任务?

注意:AB函数都没有向事件循环添加任何新任务。

var callbacks = [];
// then add a bunch of callbacks ... (none adds events to event queue)
//case 1:
callbacks.forEach(cb => setTimeout(cb,0))
//case 2:
setTimeout(function() {
   callbacks.forEach(cb => cb());
},0);

case 1case 2的回调执行顺序有何不同?

4 个答案:

答案 0 :(得分:3)

  

是否保证B会立即在A之后运行?

立即,不,但保证B将在A之后运行。完整详细信息in the spec,但简而言之,timer initialization steps中明确说明了这一点:

  

等到此算法的任何具有相同方法上下文的调用(在此之前开始,并且其超时等于或小于此值)已完成。

     

(可选)等待用户代理定义的另一段时间。

     

将任务任务排队。

...其中任务是调用您提供的回调setTimeout的任务。

任务队列必须按顺序运行,因此A将在兼容浏览器上B之前运行。

请注意,这是有保证的,因为它们是由相同的方法上下文排队的(有关详细信息,请参阅规范)。

  

浏览器是否可能在A和B之间的队列中添加另一个任务?

是。浏览器可以是多线程的,并在排队AB的任务之间为某个其他事物(来自Web工作者的消息等)排队任务。在这种情况下,您会看到A运行,然后是其他任务的处理程序(处理来自Web工作者的消息或其他任何内容),然后B

答案 1 :(得分:2)

他们将始终以正确的顺序触发,A然后B。但是,他们可能不会连续发射。

实际上,the specification says超时回调甚至没有放在执行队列上,直到计时器结束,这可能会受到额外的延迟 - 你指定的超时只是最小值等待的时间。

答案 2 :(得分:1)

JavaScript使用事件队列作为计时器。

enter image description here

另见本文: Excellent and still actual article about timers in JavaScript by John Resig.

答案 3 :(得分:-1)

是的,如果你试试这个:

function A() { console.log('A'); }
function B() { console.log('B'); }
function C() { while(1) { console.log('C'); } }
// and then i setTimeout(fn, 0) both of them
setTimeout(A, 0);
setTimeout(C, 0);
setTimeout(B, 0);

您将看到函数C具有无限循环,因此它永远不会执行函数B. 这是因为传递给任务/事件列表的函数在这些函数结束时运行。这与事件列表有关.setTimeout具有特定的工作方式。 但是,如果你问。

另一方面,如果您要求首先执行该案例,然后再执行B,则答案不能保证,因为它们不是唯一可以运行的事件。