这是我的测试代码(小提琴here):
console.log('Before wait');
setTimeout(function () { console.log('Yo!'); }, 1000);
var start = Date.now();
while (Date.now() < start + 3000) {}
console.log('After wait');
这是Chrome中事件的时间轴:
此行为是否符合规范?为什么不是
答案 0 :(得分:32)
JavaScript是单线程的。如果某些代码块使用执行线程,则不能执行其他代码。这意味着您的setTimeout()
调用必须等到主执行(忙于等待while
循环的那个)完成。
以下是发生的情况:您安排setTimeout()
在一秒钟后执行,然后阻止主线程3秒钟。这意味着忙碌循环结束的那一刻,超时已经太迟了2秒 - 并且JS引擎试图通过尽快调用你的超时来保持 - 也就是说,立即。
实际上这是:
while (Date.now() < start + 3000) {}
是JavaScript中最糟糕的事情之一。您持有JavaScript执行线程3秒钟,并且不能执行其他事件/回调。通常,浏览器会在那段时间内“冻结”。
答案 1 :(得分:8)
setTimeout
的延迟与调用它的确切时间点有关。当你还在忙着等待时,它会过期。因此它将在下一个控制重新进入事件循环的瞬间执行。
编辑:
规范在这一点上有点模糊,但我想这是有意和唯一直接的解释:
setTimeout(function,milliseconds)
此方法在经过指定的毫秒数后调用该函数,直到通过调用clearTimeout取消。该 methods返回一个timerID,可以在后续调用中使用 clearTimeout取消间隔。
答案 2 :(得分:2)
当你在setTimeout调用之后运行忙等待循环时,你没有时间为你的“哟!”打印出来,因为Javascript运行时忙着你的循环(实际上空语句也因为循环条件的继续循环而使它忙碌)。
你应该总是避免这样一个繁忙的等待循环,因为在完成之前,没有其他任何东西可以在那个窗口中调用或运行。
答案 3 :(得分:0)
不确定是否可以帮助您,但是此问题的解释如下: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Run-to-completion
因此,第二个参数表示最短时间,而不是保证时间。