在node.js中始终运行函数
为了让一个函数的单个实例始终运行,以下方法在某一点之后会有问题吗在node.js中始终运行函数,node.js,promise,ecmascript-6,q,Node.js,Promise,Ecmascript 6,Q,为了让一个函数的单个实例始终运行,以下方法在某一点之后会有问题吗 const Q = require('q'); (function main() { Q.fcall(somePromiseFunction).then(_ => { main(); }); })(); 我想知道一段时间后递归内存堆栈是否会溢出,程序是否会终止?令人惊讶的是,不会!我相信你的代码应该运行良好 JavaScript中的异步操作,如setTime
const Q = require('q');
(function main() {
Q.fcall(somePromiseFunction).then(_ => {
main();
});
})();
我想知道一段时间后递归内存堆栈是否会溢出,程序是否会终止?令人惊讶的是,不会!我相信你的代码应该运行良好 JavaScript中的异步操作,如
setTimeout()
,XMLHttpRequest
,和Promise
利用称为的东西在程序的正常流之外执行。实际上,当异步发生时,它会被添加到“队列”(与堆栈完全分离)中。堆栈清空后,事件循环将开始处理这些排队消息,逐个执行它们的相关函数
JavaScript中几乎所有异步的东西都是这样工作的,其中包括Q promises库。在你的例子中,这是一个(非常)简单的解释:
- 调用
,创建新的堆栈帧main()
- 调用
,创建第二个堆栈帧(当调用Q.fcall(somePromiseFunction)
时,可能是第三个堆栈帧)。这将在后台启动异步操作,将函数传递给somePromiseFunction
然后设置为回调
现在已返回,因此这些堆栈帧将被清除Q.fcall(somePromiseFunction)
也到了末尾,所以也被清除了-我们回到了一个空堆栈main()
- 异步操作完成后,一条消息被推送到事件队列上,然后您的
回调与之关联
- 堆栈为空,因此事件循环开始处理
- 您的回调将被执行
然后
回调只能从事件队列中调用,而不是通过main()
,因此堆栈能够在迭代之间清除而不会出现问题
我建议观看演讲,了解更多关于这一切如何运作的信息——他们解释这一切的方式最终让我感到满意
编辑:
为了回答您在评论中提出的问题,我将澄清几件事。递归函数最简单的形式如下所示:
function recursive() {
recursive();
}
调用一个函数会分配一个堆栈帧,当它返回时会被清除。但是,如果没有某种方式打破循环,像这样的递归函数永远不会返回-它只会继续,无休止地分配堆栈帧,直到出现堆栈溢出错误。这并不意味着你永远不应该使用rJavaScript中的ecursion-有时它非常有用!但是您需要注意,如果它递归太多而没有返回,那么您将到达堆栈的顶部
在回答您的另一个问题时,事件循环/回调并没有等待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!
令人惊讶的是,没有!我相信您的代码应该运行良好 JavaScript中的异步操作,如
setTimeout()
,XMLHttpRequest
,和Promise
利用称为的东西在程序的正常流之外执行。实际上,当发生异步时,它会被添加到“队列”(与堆栈完全分离)中。堆栈清空后,事件循环将开始处理这些排队的消息,逐个执行其关联的函数
JavaScript中几乎所有异步的东西都是这样工作的,其中包括Q promises库。因此在您的示例中,这是一个(非常)简化的解释:
- 调用
,创建新的堆栈帧main()
- 调用
,创建第二个堆栈帧(当调用Q.fcall(somePromiseFunction)
时,可能是第三个堆栈帧)。这将在后台启动异步操作,将函数传递给somePromiseFunction
然后设置为回调
现在已返回,因此这些堆栈帧将被清除Q.fcall(somePromiseFunction)
也到了末尾,所以也被清除了-我们回到了一个空堆栈main()
- 异步操作完成后,一条消息被推送到事件队列上,然后您的
回调与之关联
- 堆栈为空,因此事件循环开始处理
- 您的回调将被执行
然后
回调只能从事件队列中调用,而不是通过main()
,因此堆栈能够在迭代之间清除而不会出现问题
我建议观看演讲,了解更多关于这一切如何运作的信息——他们解释这一切的方式最终让我感到满意
编辑:
为了回答您在评论中提出的问题,我将澄清几件事。递归函数最简单的形式如下所示:
function recursive() {
recursive();
}
调用一个函数会分配一个堆栈帧,当它返回时会被清除。但是,如果没有某种方式打破循环,像这样的递归函数永远不会返回-它只会继续,无休止地分配堆栈帧,直到出现堆栈溢出错误。这并不意味着你永远不应该使用rJavaScript中的ecursion——有时它可能非常有用!但是您需要注意,如果它在没有返回的情况下递归太多,那么您将