棘手的setTimeout序列

时间:2015-06-10 14:49:34

标签: javascript settimeout

setTimeout调用的集合,间隔为0,1,2,3。



function f() {

    setTimeout(function a() {console.log(10);}, 3);

    setTimeout(function b() {console.log(20);}, 2);

    setTimeout(function c() {console.log(30);}, 1);

    setTimeout(function d() {console.log(40);}, 0);

}

f();




输出:(来自chrome。希望在其他浏览器中也是一样)

30

40

20

10

有人可以清楚地解释为什么订购不是30,40,10,20? 据说浏览器保持最小10毫秒或(规格说)4毫秒间隔。如果是这样,请使用时间度量标准或以便于解释此行为的方式验证输出。我错过了什么细节才能理解这种语言的这个特色?

编辑:

我知道这些函数是异步的。我读过John Resig'博客几次。我知道一个setTimeout'回调不保证以指定的间隔执行。

更准确地说,我希望有一个解释可以解释执行队列,事件循环,调用堆栈和计时器方面的行为。

2 个答案:

答案 0 :(得分:1)

  

为了理解定时器如何在内部工作,有一个   需要探索的重要概念:定时器延迟不是   保证。由于浏览器中的所有JavaScript都在单个上执行   线程异步事件(例如鼠标点击和计时器)只是   在执行中有一个开放时运行。

有关详细信息,请参阅thisthis

答案 1 :(得分:1)

正如@Jebin在对OP的评论中指出的那样,你在这里遇到了竞争条件。

以下是规范https://html.spec.whatwg.org/multipage/webappapis.html#dom-windowtimers-settimeout

步骤13是我们等待的地方,当脚本当前正在执行时,等待可能会发生。请参阅http://jsbin.com/faguli/edit?js,console - 在此示例中" 10"首先记录,因为脚本需要很长时间才能到达下一个setTimeout

据猜测,在Chrome中,第三个setTimeout的任务在JS管理对setTimeout的第四次调用之前排队。

因此,在这种情况下,Chrome和Firefox都符合规范,尽管给出了不同的答案。

实现此确定性的一种方法是将setTimeout调用作为微任务的一部分进行处理,并从那里启动计时器,但setTimeout是一个olllllld API,因此这里的更改可能会破坏Web