递归调用异步函数

8

我有一个异步函数,想要连续调用多次。

问题是,“多次”可能是几十万或数百万次...

显而易见的方法是从回调函数中再次调用相同的函数:

function foo()
{
    asyncBar(foo);
}

当然,需要一些逻辑来停止递归。问题是堆栈是否会填充调用并在某些时候导致堆栈溢出?


没有 - Bergi
为什么不直接运行程序并在开发工具中查看堆栈? - user663031
3个回答

13

问题是堆栈是否正在充满调用,并可能导致在某一点上出现stackoverflow错误?

不会。 如果asyncBar()异步调用传递的回调函数,则不会有堆栈积累。

在您的代码中:

function foo() {
    asyncBar(foo);
}

这里是正在发生的事情,逐步解释:

  1. 首先调用了 foo()
  2. 然后它调用了 asyncBar(foo)
  3. 由于 asyncBar 是异步的,这意味着它启动了一个异步操作(假设它是一个 http GET 请求,但任何异步操作都可以)。异步操作被初始化,但是 asyncBar() 立即返回。
  4. foo() 的初始调用返回,并且堆栈完全展开。现在堆栈中没有 foo() 了。
  5. 在调用 foo() 之后的任何代码都会继续运行,直到完成并返回到事件循环。
  6. 与此同时,异步操作将在未来的某个时候完成。这将在事件队列中放置对您回调的调用。
  7. 当 JS 引擎执行其他 Javascript 完毕(这意味着堆栈已完全清空)时,它将该事件从事件队列中取出并调用回调。
  8. 在这种情况下,回调函数是 foo,所以它调用该函数并重新开始整个循环,回到步骤 2。

没有堆栈积累。关键在于异步回调会在当前堆栈结束、展开并返回到系统后的某个时间点被调用。


1

问题是堆栈是否正在填充调用,并可能在某些点上导致堆栈溢出?

如果该方法是异步的,那么您将根本不会遇到stackoverflow

请查看下面的示例

function f1(n)
{
   if (n > 0 ) 
   {
       callAsynch(n, function(n){
          f1(n-1)
       });
   }
}

这个callAsynch可能是一个Ajax调用(或任何异步操作),它将回调方法作为参数传递。
由于每个调用都以对异步方法的调用结束,该方法不会将值返回给此方法,而只是在完成后将任务(调用f1(n-1))附加到队列中,因此它不会在堆栈上积累。

0

在异步调用的情况下没有堆栈溢出问题。
此外,您可以使用async模块的during方法link,递归调用异步函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接