【问题标题】:Avoid a recursive stack overflow in promise-based loop? [duplicate]在基于承诺的循环中避免递归堆栈溢出? [复制]
【发布时间】:2015-07-15 07:09:49
【问题描述】:

作为一个简单的示例程序,我有一个节点脚本,它不断地 ping 一个服务器,并希望这个程序能够运行很长时间。

程序被设置为一个 ping 函数,它返回一个 promise 对象。根据 ping 是否有效来解决或拒绝承诺。

我希望这个函数在一个循环中运行,所以无论 ping 是否成功,下一个 ping 都会在一定时间后触发 上一个请求之后解决了。​​

问题不在于这个任务本身,而是我担心我的实现。我相信它最终会导致堆栈溢出。

这里有一些代码可以查看发生了什么:

function doPing(host) {
    // returns a promise object.
}

function doEvery(ms, callback, callbackArgs) {

    setTimeout(function() {

        callback.apply(null, callbackArgs)
            .always(function() {

                doEvery(ms, callback, callbackArgs);

            });

    }, ms);

}

doEvery(1000, doPing, [host]);

我试图限制代码只是为了反映以下问题的范围:

这最终会导致堆栈溢出吗? 在使用 Promise 时,是否有一种模式可以防止基于回调的循环溢出?

【问题讨论】:

  • 为重复的问题道歉 - 有问题的问题没有出现在最初的搜索中,或者在编写问题时。我相信这个问题更具体。链接的问题是基于意见的,而我尽量保持客观和具体到基于 Promise 的循环。

标签: javascript node.js loops recursion promise


【解决方案1】:

这里没有堆栈溢出。 setTimeout 是一个异步函数:它调度要运行的函数,但不会立即调用它。由于对doEvery 的重复调用在setTimeout 的回调中,这将确保它不会溢出。

下面是最深堆栈在不同点的样子的示例:

  • 在安排第一次 ping 时:[global scope] -> doEvery -> setTimeout
  • 运行第一次 ping 时:[event loop] -> [handle timer] -> [closure #1 in doEvery] -> callback.apply -> doPing
  • 收到第一个响应时:[event loop] -> [handle network] -> promise.resolve -> [closure #2 in doEvery] -> doEvery -> setTimeout
  • 第二次超时时:[event loop] -> [handle timer] -> [closure #1 in doEvery] -> callback.apply -> doPing

如您所见,每次等待承诺或超时时,控制权都会返回到事件循环。当事件(例如超时或收到 ping 响应)时,事件循环会调用为该事件注册的回调。

【讨论】:

  • 谢谢。我担心异步函数仍然会导致堆栈增长。
猜你喜欢
  • 1970-01-01
  • 2018-10-29
  • 1970-01-01
  • 2013-06-28
  • 2014-04-13
  • 2011-08-15
  • 2020-03-08
  • 1970-01-01
  • 2015-11-22
相关资源
最近更新 更多