[英]running a function all the time in node.js
为了始终有一个函数的单个实例一直运行,在某种情况下以下方法会出现问题吗?
const Q = require('q');
(function main() {
Q.fcall(somePromiseFunction).then(_ => {
main();
});
})();
我想知道一段时间后递归内存堆栈是否会溢出并且程序是否终止?
令人惊讶的是,不! 我相信您的代码应该可以正常运行。
JavaScript中的异步操作(例如setTimeout()
, XMLHttpRequest
和Promise
利用称为事件循环的事件在程序的正常流程之外执行。 实际上,当异步发生时,它会添加到“队列”(与堆栈完全分离)中。 堆栈清空后,事件循环将开始处理这些排队的消息,并逐一执行它们的关联功能。
JavaScript中几乎所有异步的东西都是以这种方式工作的,其中包括Q promises库。 因此,在您的示例中,这是(非常)简化的解释:
main()
被调用,创建一个新的堆栈框架。 Q.fcall(somePromiseFunction)
被调用时,创建第二堆栈帧(并且假定第三,当somePromiseFunction
被调用。该衬托异步操作的背景下,与通过了功能then
设置为回调。 Q.fcall(somePromiseFunction)
现在已经返回,因此那些堆栈帧被清除了。 main()
也已到达末尾,因此也被清除了-我们回到了一个空堆栈。 then
与之相关联的回调。 这里要注意的重要一点是您的代码不会递归 ! 您的then
回调只会从事件队列中调用,而不会通过main()
进行调用,因此堆栈可以在两次迭代之间清除而不会出现问题。
我建议您观看演讲“无论如何,事件循环到底是什么?” 有关这一切如何工作的更多信息-他们的解释方式是让它最终对我点击的原因。
编辑:为了回应您在评论中的问题,我将澄清一些事情。 最简单形式的递归函数如下所示:
function recursive() {
recursive();
}
调用一个函数会分配一个堆栈帧,该堆栈帧在返回时会清除。 但是,如果没有某种打破循环的方式,那么像这样的递归函数将永远不会返回-它只会继续运行,不断分配堆栈帧,直到出现堆栈溢出错误为止。 但这并不意味着您永远不要在JavaScript中使用递归-有时它会很有用! 但是您需要注意,如果递归太多而又没有返回,那么您将到达堆栈的顶部。
在回答您的另一个问题时-事件循环/您的回调不特别等待main()
结束,它仅等待堆栈清除。 这是堆栈在程序中的作用的简化可视化:
[]
[main]
[main, fcall]
[main, fcall, somePromiseFunction]
[main, fcall]
[main]
[main, then]
[main]
[] // Main returned, so the stack is clear
[yourCallback] // The event loop kicks in, runs your callback
[yourCallback, main]
... // Above steps repeat
[yourCallback] // Main returned
[] // Stack clears, so the event loop kicks in again
将此与我不断重复的功能进行比较:
[]
[recursive]
[recursive, recursive] // Nothing stops the recursion,
[recursive, recursive, recursive] // so the stack is never going to clear!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.