This question already has answers here:
Is this type of recursion bad in JavaScript? If so, how should I rewrite it? [closed]

(2个答案)


已关闭6年。




作为一个简单的示例程序,我有一个 Node 脚本,该脚本连续ping服务器,并希望该程序能长时间运行。

该程序被设置为可返回Promise对象的ping函数。根据ping是成功还是失败,来兑现或拒绝 promise 。

我希望此功能循环运行,因此无论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]);

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

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

最佳答案

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

这是最深的堆栈在各个点上可能看起来像的示例:

  • 安排第一次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

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

    关于javascript - 避免在基于promise的循环中递归堆栈溢出?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30054859/

    10-16 20:58