我已经在事件循环中阅读了多个帖子/ SO帖子,并根据MDN's article,
当堆栈为空时,会从队列中取出一条消息 处理。
作为JS的新手,我仍然感到困惑的是 - 当调用堆栈确实变为"空的时候#34;?例如,
<script>
function f() {
console.log("foo");
setTimeout(g, 0);
console.log("foo again");
}
function g() {
console.log("bar");
}
function b() {
console.log("bye");
}
f();
/*<---- Is the stack empty here? */
b();
</script>
正确的执行顺序是foo
- foo again
- bye
- bar
。
但是今天我开始思考:退出f()
电话后,技术上堆栈是不是很空?我的意思是在那一点上我们不在任何函数内部,并且我们还没有开始任何新的执行,所以不应该处理setTimeout
调用消息(已经立即排队) ,然后转到b()
,并提供foo
- foo again
- bar
- bye
的订单?
如果我们要执行a million lines of code或一些密集计算并且setTimeout(func, 0)
只是在队列中待了多长时间怎么办?
答案 0 :(得分:8)
尽管<script>
标记中的代码块未包含在显式函数中,但将其视为浏览器告知javascript运行时执行的全局函数会有所帮助。因此,在脚本块中的代码执行完毕之前,调用堆栈不为空。
答案 1 :(得分:4)
当正在执行的当前Javascript片段已经完成且没有更多顺序指令要执行时,那么JS引擎才会将下一个项目拉出事件队列。
所以,在你的例子中:
f();
b();
// JS is done executing here so this is where the next item will be
// pulled from the event queue to execute it
Javascript是单线程的,这意味着Javascript的当前线程运行完成,执行序列中的所有指令,直到它到达代码的末尾。然后,只有这样,它才会从事件队列中提取下一个项目。
以下是其他一些可能有助于您理解的答案:
How does JavaScript handle AJAX responses in the background?(这篇文章中的一大堆事件循环引用)
Do I need to be concerned with race conditions with asynchronous Javascript?
Can JS event handlers interrupt execution of another handler?
答案 2 :(得分:2)
我能想到解释它的最好方法是,在代码完成所有相关路径的运行之前,调用堆栈不为空。 setTimeout为0只是将代码推送到堆栈的末尾。
当代码在运行时运行时,将运行的所有内容都是调用堆栈的一部分,订单将根据调用的顺序和任何超时/间隔/异步方法进行调整调用。
一些例子:
function foo() {
console.log('foo');
}
function bar() {
baz();
console.log('bar');
}
function baz() {
setTimeout(function() { console.log('timeout') }, 0);
console.log('baz');
}
foo();
baz();
// call stack ends here, so, timeout is logged last.
// in console
// foo
// baz
// timeout
如您所见,bar未包含在运行时堆栈中,因为它未被调用。如果我们有一些HTML:
<div onclick="bar()">Bar runs</div>
当您单击该div时,您将看到baz
,bar
,然后timeout
已登录到控制台,因为超时始终被推送到当前正在运行的进程的末尾/调用堆栈。
希望这个解释有所帮助!
答案 3 :(得分:2)
最简单的解释:当前脚本,函数或事件处理程序中的所有同步代码都已完成运行。
直接回答“如果我有数百万行...”是的 - 你的setTimeout
来电已停留在队列中并等待轮到。