带有阻塞代码的setTimeout行为

问题描述 投票:5回答:4

这是我的测试代码(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浏览器中事件的时间轴。

  • 时间0秒。打印 "等待之前"
  • 时间3秒。打印 "等待后",然后紧接着打印 "哟!"

这种行为符合规范吗?为什么不符合规范?

  • 时间0秒。打印 "等待之前"
  • 时间3秒。打印 "等待之后"
  • 时间4分钟 打印 "哟!"

?

javascript settimeout
4个回答
9
投票

的延迟。setTimeout 是相对于它被调用的确切时间点而言的。当你还在忙着等待的时候,它就会失效。所以它将在下一个控制回到事件循环的瞬间执行。

编辑。

规范在这一点上有点模糊,但我想这是预期的,也是唯一直接的解释。

setTimeout(function, milliseconds)

该方法在指定的毫秒数过后调用该函数一次,直到被调用clearTimeout取消。该方法返回一个 timerID,它可以用于后续调用 clearTimeout 来取消间隔。


47
投票

JavaScript是单线程的。如果某些代码块使用了执行线程,其他代码就不能执行。这意味着你的 setTimeout() 调用必须等到主执行(有忙于等待的 while 循环)完成。

事情是这样的:你安排了 setTimeout() 秒后执行,然后阻塞主线程3秒。这意味着当你的忙环完成的那一刻,超时已经晚了2秒--JS引擎试图跟上你的节奏,尽快调用你的超时,也就是立即调用。

事实上这。

while (Date.now() < start + 3000) {}

是JavaScript中最糟糕的事情之一。你保持JavaScript执行线程3秒,其他的eventcallback都无法执行。通常浏览器会在这段时间内 "冻结"。


2
投票

当你在setTimeout调用后运行忙等待循环时,你没有时间让你的 "Yo!"打印出来,因为Javascript运行时正忙于你的循环(实际上空语句也会使它忙于循环条件的继续执行)。

你应该总是避免这样一个繁忙的等待循环,因为在循环完成之前,没有任何其他的东西可以被调用或在该窗口中运行。


0
投票

不知道是否能帮到你,但这个问题已经在以下文章中解释过了。https:/developer.mozilla.orgen-USdocsWebJavaScriptEventLoop#Run-to-completion中解释了这个问题。

出于这个原因,第二个参数表示的是最短的时间,而不是保证的时间。

© www.soinside.com 2019 - 2024. All rights reserved.