JavaScript - 调用堆栈究竟何时变为 "empty"?
JavaScript - When exactly does the call stack become "empty"?
我已经阅读了几个关于事件循环的 posts/SO 线程,并且根据 MDN's article、
When the stack is empty, a message is taken out of the queue and
processed.
作为一个JS新手,我还比较困惑的是——调用栈到底什么时候变成了"empty"?例如,
<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()
调用后堆栈在技术上不是空的吗?我的意思是那时我们不在任何函数中,我们还没有开始任何新的执行,所以在继续 b()
,并给出 foo
- foo again
- bar
- bye
?
的顺序
如果我们有 a million lines of code 或一些密集的计算要执行,而 setTimeout(func, 0)
只是在队列中停留了很长时间怎么办?
当当前正在执行的 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 是 single-threaded,这意味着 Javascript 的当前线程运行到完成,执行一个序列中的所有指令,直到它到达代码末尾。然后,并且只有在那时,它才会从事件队列中拉出下一个项目。
以下是一些可能有助于您理解的其他答案:
How does JavaScript handle AJAX responses in the background?(在此 post 中引用了一大堆事件循环)
Do I need to be concerned with race conditions with asynchronous Javascript?
Can JS event handlers interrupt execution of another handler?
我能想到的最好的解释方法是,在代码完成 运行所有相关路径之前,调用堆栈不为空。 setTimeout 为 0 只是将您的代码推到堆栈的末尾。
当代码 运行s 在 运行 时, 将 成为 运行 的所有内容都是调用堆栈的一部分,顺序将根据调用的顺序和调用的任何 timeouts/intervals/async 方法进行调整。
一些示例:
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
记录到控制台,因为超时总是推到最后当前 运行 宁 processes/call 堆栈。
希望这个解释对您有所帮助!
最简单的解释:当当前脚本、函数或事件处理程序中的所有同步代码都已完成时运行。
直接回答 "what if I have millions of lines..." 是 - 你的 setTimeout
电话被困在队列中,将等待轮到它。
虽然 <script>
标签中的代码块没有包含在显式函数中,但将其视为浏览器告诉 javascript 的全局函数可能会有所帮助要执行的运行时。因此,在脚本块中的代码执行完毕之前,调用堆栈不会为空。
我已经阅读了几个关于事件循环的 posts/SO 线程,并且根据 MDN's article、
When the stack is empty, a message is taken out of the queue and processed.
作为一个JS新手,我还比较困惑的是——调用栈到底什么时候变成了"empty"?例如,
<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()
调用后堆栈在技术上不是空的吗?我的意思是那时我们不在任何函数中,我们还没有开始任何新的执行,所以在继续 b()
,并给出 foo
- foo again
- bar
- bye
?
如果我们有 a million lines of code 或一些密集的计算要执行,而 setTimeout(func, 0)
只是在队列中停留了很长时间怎么办?
当当前正在执行的 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 是 single-threaded,这意味着 Javascript 的当前线程运行到完成,执行一个序列中的所有指令,直到它到达代码末尾。然后,并且只有在那时,它才会从事件队列中拉出下一个项目。
以下是一些可能有助于您理解的其他答案:
How does JavaScript handle AJAX responses in the background?(在此 post 中引用了一大堆事件循环)
Do I need to be concerned with race conditions with asynchronous Javascript?
Can JS event handlers interrupt execution of another handler?
我能想到的最好的解释方法是,在代码完成 运行所有相关路径之前,调用堆栈不为空。 setTimeout 为 0 只是将您的代码推到堆栈的末尾。
当代码 运行s 在 运行 时, 将 成为 运行 的所有内容都是调用堆栈的一部分,顺序将根据调用的顺序和调用的任何 timeouts/intervals/async 方法进行调整。
一些示例:
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
记录到控制台,因为超时总是推到最后当前 运行 宁 processes/call 堆栈。
希望这个解释对您有所帮助!
最简单的解释:当当前脚本、函数或事件处理程序中的所有同步代码都已完成时运行。
直接回答 "what if I have millions of lines..." 是 - 你的 setTimeout
电话被困在队列中,将等待轮到它。
虽然 <script>
标签中的代码块没有包含在显式函数中,但将其视为浏览器告诉 javascript 的全局函数可能会有所帮助要执行的运行时。因此,在脚本块中的代码执行完毕之前,调用堆栈不会为空。