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
答案 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(据我所知)。