2015-10-13 41 views
2

我细读了一套在线的JavaScript的面试问题,发现以下问题:理解的setTimeout为了

function printing() { 
    console.log(1); 
    setTimeout(function() { console.log(2); }, 1); 
    setTimeout(function() { console.log(3); }, 2); 
    setTimeout(function() { console.log(4); }, 0); 
    console.log(5); 
} 
printing(); 

我期待下面的代码以下内容打印到控制台:1,5,4,3 ,2 我的理由是console.log(1)和console.log(2)首先被执行,而setTimeout被发送到eventloop,并等待所有事情先完成。一旦打印出5,JS就会查看队列,并且4,3,2会在下一个按下/弹出。

但是,在我的Chrome浏览器中,我注意到1,5,2,4,3代替。

我很困惑,但同时有一个预感,它可能是由于超时延迟的小增量导致打嗝(也许是浏览器的事?)。我之所以这样做,是因为我为每个数字添加了两个零以便延迟变为100,200和0。

任何人都可以澄清引擎盖下发生了什么,以及任何我应该了解延迟的细节?

+1

很确定超时的最小有效值是1,所以0移到1,因此发生在之后。不确定。无论如何,我不会使用小于16ms的定时器(60Hz),因为这是Windows的默认定时器分辨率,我不想仅仅为了使用高分辨率定时器。 –

+0

我注意到下面的链接,其中最小值为4ms和10ms取决于浏览器:http://stackoverflow.com/questions/9647215/what-is-minimum-millisecond-value-of-settimeout – bigbitecode

+0

这可能是值得注意的是,在[w3 spec](http://www.w3.org/TR/html5/webappapis.html)第6.4节规定'... timeout小于4,然后增加超时到4'(如果你的ms值是根据规范0-3它将被设置为4),并且与此同时,您可能会发现以下有关Javascript计时的有用信息[Javascript Javascript定时器如何工作](http://ejohn.org/blog/how-javascript-timers-工作/) –

回答

3

这里我给你的执行如何去一个例子:

console.log(1);         // Run log "1" 
    setTimeout(function() { console.log(2); }, 1); // Add to queue timer1 
    setTimeout(function() { console.log(3); }, 2); // Add to queue timer2 
    setTimeout(function() { console.log(4); }, 0); // Add to queue timer3 
    console.log(5);         // Run log "5" 
    // In queue [timer1, timer2, timer3] 

    // [tick timer 1 => 0 time left => execute] log "2" 
    // [tick timer 2 => 1 time left] 
    // [timer 3 => 0 time left => execute] log "4" 
    // [tick timer 2 => 0 time left => execute] log "3" 

功能setTimeout(... , 0)setTimeout(..., 1)将同样的方式工作。当我们在“超时队列”中勾选每个定时器时,我们也检查是否还有剩余时间。所以setTimeout(..., 1)将会打勾并执行,而setTimeout(... , 0)将会执行。

+0

啊,这很有道理。由于JS是同步的,它将按照定时器队列的顺序执行,并首先使timer1到期,使其执行。真正有用的评论,谢谢! – bigbitecode

+0

每个浏览器/引擎都一样吗?我的firefox日志'1 5 4 2 3' – Anonymous0day

+0

@ Anonymous0day不,不是。不同的浏览器可以以不同的方式处理定时器。我上面解释的是它在OP浏览器中发生的情况(我认为它会是chrome)。它看起来像Firefox会以不同的方式在队列中的每个计时器上进行打勾(它可能会以最小的时间先打勾,但这是一个猜测)。 –

0

您必须了解调用堆栈。所有函数调用都放置在调用堆栈上,如果堆栈为空,则调用该函数。如果堆栈有条目,那么直到堆栈上的当前调用完成才会调用该函数。

当超时时,超时将调用置于调用堆栈上。他们异步执行此操作。因此可以在当前执行期间将调用放置在调用堆栈上。

超时未优先,堆栈中的第一个执行。 1毫秒超时将跳过调用堆栈的0毫秒,因此首先执行。