Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/369.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript:为什么递归获胜';停不下来?_Javascript_Asynchronous_Recursion_Callback_Settimeout - Fatal编程技术网

JavaScript:为什么递归获胜';停不下来?

JavaScript:为什么递归获胜';停不下来?,javascript,asynchronous,recursion,callback,settimeout,Javascript,Asynchronous,Recursion,Callback,Settimeout,如果我将foo++包装在setTimeout中,为什么递归不会停止?我很确定我错过了一个关于异步操作的主要JavaScript概念 设foo=0; 常数条=()=>{ setTimeout(()=>foo++); 如果(foo当您调用bar()时,它会被添加到名为的内容中。调用堆栈用于跟踪我们在脚本中调用函数和从函数返回时的位置。当调用函数时,它会被添加到调用堆栈中,当它返回时,它会从调用堆栈中弹出 Stack: - bar() Stack: - bar() // after first r

如果我将
foo++
包装在
setTimeout
中,为什么递归不会停止?我很确定我错过了一个关于异步操作的主要JavaScript概念

设foo=0;
常数条=()=>{
setTimeout(()=>foo++);
如果(foo当您调用
bar()
时,它会被添加到名为的内容中。调用堆栈用于跟踪我们在脚本中调用函数和从函数返回时的位置。当调用函数时,它会被添加到调用堆栈中,当它返回时,它会从调用堆栈中弹出

Stack:
- bar()
Stack:
- bar() // after first recursive call
- bar()
当运行
bar()
时,它调用
setTimeout()
,该调用被添加到调用堆栈中

Stack:
- bar()
Stack:
- bar() // after first recursive call
- bar()
setTimeout()
函数启动Web API并完成/返回,将其从调用堆栈中弹出。然后,Web API等待0毫秒(0毫秒,当没有延迟传递给setTimeout时,它默认为0),并将您的
()=>foo++
回调推送到任务队列上

Task queue: (front ---- back)
() => foo++
只有在调用堆栈为空时,事件循环才会将任务队列中的任务弹出/退出队列。这一点很重要,因为这意味着只有在返回
bar()
后才会调用上述以
foo
为增量的回调(从而将其弹出调用堆栈),但是,这不会发生,因为
bar()
继续不断地调用自身,因为if条件始终为true,因此将继续向调用堆栈添加
bar()

Stack:
- bar()
Stack:
- bar() // after first recursive call
- bar()
在递归函数中继续调用
bar()
时,调用堆栈开始填满,任务队列也开始填满:

Stack:
- bar() // after N recursive calls
...
- bar()
- bar()
由于您的调用堆栈从来没有机会将bar()弹出堆栈,因此它会继续增长,从而出现“超出最大调用堆栈大小”错误。

当您调用
bar()时
它被添加到名为的内容中。调用堆栈用于在调用函数和从函数返回时跟踪脚本中的位置。当调用函数时,它被添加到调用堆栈中,当它返回时,它从调用堆栈中弹出

Stack:
- bar()
Stack:
- bar() // after first recursive call
- bar()
当运行
bar()
时,它调用
setTimeout()
,该调用被添加到调用堆栈中

Stack:
- bar()
Stack:
- bar() // after first recursive call
- bar()
setTimeout()
函数启动Web API并完成/返回,将其从调用堆栈中弹出。然后,Web API等待0毫秒(0毫秒,当没有延迟传递给setTimeout时,它默认为0),并将您的
()=>foo++
回调推送到任务队列上

Task queue: (front ---- back)
() => foo++
只有在调用堆栈为空时,事件循环才会将任务队列中的任务弹出/退出队列。这一点很重要,因为这意味着只有在返回
bar()
后才会调用上述以
foo
为增量的回调(从而将其弹出调用堆栈),但是,这不会发生,因为
bar()
继续不断地调用自身,因为if条件始终为true,因此将继续向调用堆栈添加
bar()

Stack:
- bar()
Stack:
- bar() // after first recursive call
- bar()
在递归函数中继续调用
bar()
时,调用堆栈开始填满,任务队列也开始填满:

Stack:
- bar() // after N recursive calls
...
- bar()
- bar()

由于调用堆栈从来没有机会将bar()弹出堆栈,因此它会继续增长,从而出现“超出最大调用堆栈大小”错误。

您应该将递归放在setTimeout回调中:

设foo=0;
常数条=()=>{
foo++;

如果(foo您应该将递归放在setTimeout回调中:

设foo=0;
常数条=()=>{
foo++;

如果(foo停止使用全局状态和副作用,你的问题就会消失-

常数延迟=
500
功能栏(foo=0)
{如果(foo>2)
回来
其他的
setTimeout(=>bar(foo+1),延迟)
console.log(foo)
}

bar()
停止使用全局状态和副作用,问题就会消失-

常数延迟=
500
功能栏(foo=0)
{如果(foo>2)
回来
其他的
setTimeout(=>bar(foo+1),延迟)
console.log(foo)
}

bar()
超时回调将在当前函数完成后的某个时间执行。但它永远不会完成。@deceze它在其中指的是什么永远不会完成?另外,众所周知,超时回调总是在某个时间后执行,我正在寻找一个深入的解释:)这是你的函数,
bar
。只需清空
setTimeout
的内容,无论出于何种目的,传递给
setTimeout
的内容都是无关的。阅读
bar
时忽略它,很明显这只是一个无休止的递归,因此它永远不会结束。@deceze抱歉地说,但解释是错误的非常模糊,建议只忽略一行代码。好吧,同样,出于所有目的和目的,您可以忽略这行代码,它不会产生任何影响。超时回调将在当前函数完成后的某个时间执行。但它永远不会完成。@deceze它在“永远不会完成”中指的是什么?另外,它是一个kn我自己的一个事实是,超时回调总是在一段时间后执行,我一直在寻找一个深入的解释:)这是你的函数,
bar
。只需清空
setTimeout
的内容,无论出于何种目的,传递给
setTimeout
的内容都是无关的。阅读
bar
时忽略它,很明显这只是一个无休止的递归,因此它永远不会结束。@deceze抱歉地说,但解释是错误的非常模糊,建议只忽略一行代码。好吧,同样,出于所有意图和目的,您可以忽略这行代码,它不会产生任何影响。请不要盲目发布解决方案,即使没有一次试运行。它不会记录3,而是记录1,因为
setTimeout
是异步的,并且在执行之前会记录foo。如果您简单地将在调用
bar()
之前增加,即