Javascript 调用setTimeout是否清除调用堆栈?
通过使用setTimeout方法调用函数而不是直接调用函数,可以避免javascript中的堆栈溢出吗?我对setTimeout的理解是,它应该启动一个新的调用堆栈。当我查看chrome和IE的调用堆栈时,似乎setTimeout调用正在等待函数调用返回 这只是调试器的属性还是我的理解有缺陷 编辑Javascript 调用setTimeout是否清除调用堆栈?,javascript,settimeout,callstack,Javascript,Settimeout,Callstack,通过使用setTimeout方法调用函数而不是直接调用函数,可以避免javascript中的堆栈溢出吗?我对setTimeout的理解是,它应该启动一个新的调用堆栈。当我查看chrome和IE的调用堆栈时,似乎setTimeout调用正在等待函数调用返回 这只是调试器的属性还是我的理解有缺陷 编辑 虽然下面提供的答案是正确的,但我遇到的实际问题与调用setTimeout(affunction(),10)有关,因为括号的缘故,setTimeout正在立即计算函数。帮我整理一下。异步调用,比如来自s
虽然下面提供的答案是正确的,但我遇到的实际问题与调用setTimeout(affunction(),10)有关,因为括号的缘故,setTimeout正在立即计算函数。帮我整理一下。异步调用,比如来自
setTimeout
的调用,确实会生成一个新的调用堆栈
当你说“当我查看chrome和IE的调用堆栈时,似乎setTimeout调用正在等待函数调用返回”时,你并不完全清楚你在描述什么。但是,你可以做的一件事是在由
setTimeout
调用的函数内放置一个断点,然后查看调用堆栈是否为空。我可以确认堆栈是否已清除
考虑以下情况:
function a() {
b();
}
function b() {
c();
}
function c() {
debugger;
setTimeout( d, 1000 );
}
function d() {
debugger;
}
a();
因此有两个断点-一个在函数c
的开头,另一个在函数d
的开头
在第一个断点处堆栈:
- c()
- b()
- ()
- d()
实时演示:还有另一种方法可以在不使用setTimeout()的情况下清除调用堆栈: testLoop.js
let counter = 0;
const max = 1000000000n // 'n' signifies BigInteger
Error.stackTraceLimit = 100;
const A = () => {
fp = B;
}
const B = () => {
fp = A;
}
let fp = B;
const then = process.hrtime.bigint();
loop: // label is not needed for this simple case though useful for some cases
for(;;) {
counter++;
if (counter > max) {
const now = process.hrtime.bigint();
const nanos = now - then;
console.log({ "runtime(sec)": Number(nanos) / (1000000000.0) })
throw Error('exit')
}
fp()
continue loop;
}
输出:
$ node testLoop.js
{ 'runtime(sec)': 20.647399601 }
C:\Users\jlowe\Documents\Projects\clearStack\testLoop.js:25
throw Error('exit')
^
Error: exit
at Object.<anonymous> (C:\Users\jlowe\Documents\Projects\clearStack\testLoop.js:25:11)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:829:12)
at startup (internal/bootstrap/node.js:283:19)
at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
$node testLoop.js
{‘运行时(秒)’:20.647399601}
C:\Users\jlowe\Documents\Projects\clearStack\testLoop.js:25
抛出错误('退出')
^
错误:退出
反对。(C:\Users\jlowe\Documents\Projects\clearStack\testLoop.js:25:11)
at模块编译(内部/modules/cjs/loader.js:776:30)
在Object.Module._extensions..js(internal/modules/cjs/loader.js:787:10)
at Module.load(内部/modules/cjs/loader.js:653:32)
在tryModuleLoad(内部/modules/cjs/loader.js:593:12)
at Function.Module._load(内部/modules/cjs/loader.js:585:3)
位于Function.Module.runMain(internal/modules/cjs/loader.js:829:12)
启动时(内部/bootstrap/node.js:283:19)
在bootstrapNodeJSCore(internal/bootstrap/node.js:622:3)
您知道为什么我仍然可以在调试器中看到整个调用堆栈吗?是因为我从setTimeout调用的函数使用闭包获取某些局部变量吗?@AranMulholland在哪里调用调试器?在传递到setTimeout
?@ŠimeVidas的函数中,根据问题,我只是在查看浏览器调试器(Chrome和IE)中的调用堆栈。如果你说他们生成了一个新的调用堆栈,那么这个家伙说它可能还必须在回调队列中等待,这是错的吗?youtu.be/8aGhZQkoFbQ?t=782调用堆栈和回调(任务)队列是完全不相关的概念。在调用的函数返回之前,不能调用传递到setTimeout
中的函数。因此,是的,该函数确实启动了一个新的调用堆栈。感谢您为我指明了正确的方向,我能够根据您的答案解决问题,但是我还有另一个问题,看看这个人是否正确,您的答案怎么可能是正确的答案?因为这家伙说它总是首先将回调推送到回调队列,而不是堆栈,所以如果调用堆栈中仍有同步命令在运行,或者堆栈中的其他东西,它必须等待甚至超过指定的毫秒。所以它并不总是1:1。这可能会发生:嘿,我给了你5秒的延迟,为什么你7秒后回来?因为回调需要再等一会儿。您通过setTimeout
的第二个参数指定的延迟并不保证在该特定时间点调用回调,true;但是我的回答并没有说会。我认为需要注意的是,d()
将在一个单独的调用堆栈中以c()
的范围调用。因此,当执行d()
时,虽然c()
已经完成了到a()
的所有过程,但它们的局部变量仍然保留在内存中,直到d()
完成,GC开始清理空间。