使用阻塞代码的setTimeout行为

Ran*_*lue 4 javascript settimeout

这是我的测试代码(在这里小提琴):

console.log('Before wait');
setTimeout(function () { console.log('Yo!'); }, 1000);
var start = Date.now();
while (Date.now() < start + 3000) {}
console.log('After wait');
Run Code Online (Sandbox Code Playgroud)

这是Chrome中事件的时间轴:

  • 时间0秒:打印"等待前"
  • 时间3秒:打印"等待后",然后立即打印"哟!"

这种行为是否符合规范?为什么不呢

  • 时间0秒:打印"等待前"
  • 时间3秒:打印"等待后"
  • 时间4 seoncds:打印"哟!"

Tom*_*icz 43

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

以下是发生的情况:您计划setTimeout()在一秒钟后执行,然后阻止主线程3秒钟.这意味着你的繁忙循环完成的那一刻,超时已经是2秒太晚了 - 而且JS引擎试图通过尽快调用你的超时来保持同步 - 也就是说,立即.

事实上这个:

while (Date.now() < start + 3000) {}
Run Code Online (Sandbox Code Playgroud)

是JavaScript中最糟糕的事情之一.您持有JavaScript执行线程3秒钟,并且不能执行其他事件/回调.通常,浏览器会在那段时间内"冻结".

  • JavaScript 是单线程的事实解释了为什么“哟!” 打印*之后*“等待之后”,仅此而已。 (2认同)

tow*_*tow 9

延迟setTimeout是相对于调用它的确切时间点.当你还在忙着等待时,它会过期.因此它将在控制返回事件循环的下一瞬间执行.

编辑:

在这一点上,规范有点模糊,但我想这是有意和唯一直接的解释:

setTimeout(函数,毫秒)

此方法在经过指定的毫秒数后调用该函数,直到通过调用clearTimeout取消.这些方法返回一个timerID,可以在后续的clearTimeout调用中取消该间隔.