Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/38.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在node.js中始终运行函数_Node.js_Promise_Ecmascript 6_Q - Fatal编程技术网

在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——有时它可能非常有用!但是您需要注意,如果它在没有返回的情况下递归太多,那么您将