避免在基于promise的循环中发生recursion堆栈溢出?

作为一个简单的例子程序,我有一个连续ping服务器的节点脚本,希望这个程序长时间运行。

程序设置为一个返回一个promise对象的ping函数。 这个承诺是根据ping是工作还是失败来解决或拒绝的。

我希望这个函数在一个循环中运行,所以无论ping是否成功,在前一个请求被parsing之后的一段时间之后 ,下一个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的基于callback的循环溢出吗?

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

这里是一个例子,最深的堆栈可能在不同的点上看起来像:

  • 调度第一个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响应)时,事件循环会调用为该事件注册的callback。