这是我的测试代码(fiddle 此处):
console.log('Before wait');
setTimeout(function () { console.log('Yo!'); }, 1000);
var start = Date.now();
while (Date.now() < start + 3000) {}
console.log('After wait');
这是Chrome浏览器中事件的时间轴。
这种行为符合规范吗?为什么不符合规范?
?
的延迟。setTimeout
是相对于它被调用的确切时间点而言的。当你还在忙着等待的时候,它就会失效。所以它将在下一个控制回到事件循环的瞬间执行。
编辑。
规范在这一点上有点模糊,但我想这是预期的,也是唯一直接的解释。
setTimeout(function, milliseconds)
该方法在指定的毫秒数过后调用该函数一次,直到被调用clearTimeout取消。该方法返回一个 timerID,它可以用于后续调用 clearTimeout 来取消间隔。
JavaScript是单线程的。如果某些代码块使用了执行线程,其他代码就不能执行。这意味着你的 setTimeout()
调用必须等到主执行(有忙于等待的 while
循环)完成。
事情是这样的:你安排了 setTimeout()
秒后执行,然后阻塞主线程3秒。这意味着当你的忙环完成的那一刻,超时已经晚了2秒--JS引擎试图跟上你的节奏,尽快调用你的超时,也就是立即调用。
事实上这。
while (Date.now() < start + 3000) {}
是JavaScript中最糟糕的事情之一。你保持JavaScript执行线程3秒,其他的eventcallback都无法执行。通常浏览器会在这段时间内 "冻结"。
当你在setTimeout调用后运行忙等待循环时,你没有时间让你的 "Yo!"打印出来,因为Javascript运行时正忙于你的循环(实际上空语句也会使它忙于循环条件的继续执行)。
你应该总是避免这样一个繁忙的等待循环,因为在循环完成之前,没有任何其他的东西可以被调用或在该窗口中运行。
不知道是否能帮到你,但这个问题已经在以下文章中解释过了。https:/developer.mozilla.orgen-USdocsWebJavaScriptEventLoop#Run-to-completion中解释了这个问题。
出于这个原因,第二个参数表示的是最短的时间,而不是保证的时间。