回调执行时间在Chrome中不符合预期

时间:2018-09-28 03:36:45

标签: javascript web-applications frontend

This blog post解释了如何在后台执行JavaScript。它描述了堆栈,事件循环,回调队列和Web api上下文。

我尝试了以下示例:

function main() {
  setTimeout( () => alert('World') , 1000 ); // don't dismiss this alert for about 5 seconds
  setTimeout( () => alert('Mars') , 5000 );
}

main();

我希望两个计时器都可以并行运行。一旦我取消了第一个警报,下一个警报就会立即出现。这是Firefox和Edge中的行为。但是在Chrome浏览器中,第二个警报会在第一个警报被撤消5秒后到来。没想到。

Chrome实施是否存在问题? Chrome是否正在尝试进行一些优化?

版本:Firefox Quantum 61.0.1,Chrome 69.0.3497.100,Edge 42.17134.1.0

2 个答案:

答案 0 :(得分:1)

关于JS的特质之一是执行环境有所不同,您似乎对可用的各种引擎不屑一顾。

在Chrome中,alert是一种阻止执行的阻止方法。

考虑以下示例:

(() => {
  for (let i = 0; i < 10; i++) {
    setTimeout(() => console.log(i), i*1000)
  }
  setTimeout(() => alert('World'), 1000)
  setTimeout(() => alert('Mars'), 5000)
})()

您将看到,该警报消除之后,计数器停止并恢复运行。但是,您通常期望在JS被认为是non-blocking的情况下是正确的,并且在大多数情况下,诸如setTimeout之类的方法将异步运行(例如在必须递增计时器的for循环中)以获得所需的行为)。

答案 1 :(得分:0)

简短的回答:请勿使用alert,这是不好的做法。使用console.log

诸如setTimeout()之类的调用是DOM API。它们不在主执行堆栈(LIFO)中运行。相反,它们被放置在运行它们的并行线程中。让我们将此称为DOM线程。

在这种情况下(第一个setTimeout = t1),t1放在DOM线程上,然后是t2,main()继续执行。当t1超时时,它的回调被放在事件队列中。当t2超时时,其回调将置于同一队列中。

然后按顺序拔出事件队列中的回调,并在主线程中执行。但是,只有当主堆栈为空且浏览器不忙时,每个快照才会发生。 setTimeout仅保证在指定时间之前不会调用该回调。

如果您要访问console.log用户而不是发出警报,则会看到代码按预期执行。使用警报是一种不好的做法,实际上会阻止您在Chrome中执行JS(据我所知)。

setTimeout with and without alert