将从回调中递归调用函数会导致堆栈溢出吗?

时间:2016-06-22 15:00:09

标签: javascript stack-overflow

我想在事件被触发后调用一个函数然后在同一个回调中再次调用该函数。这是在函数完成时创建一种事件监听器。

当您看到代码时,您会知道我想要做什么:

"use strict";
var page = require('webpage').create();
var system = require('system');

function onStdReadLine(callback) {
    system.stdin.readLineAsync(function(err, line) {
        callback(line);
        onStdReadLine(callback);
    });
}

onStdReadLine(function(line) {
    // do something when the line comes in
    system.stdout.writeLine(line);
}); 

问题:

这可能导致堆栈溢出吗?有没有办法重构这段代码不是递归的?

谢谢!

2 个答案:

答案 0 :(得分:6)

  

这可能导致堆栈溢出吗?

不,它不会导致堆栈溢出。当堆栈完全展开时调用异步回调,因此没有堆栈堆积。

记住异步操作的工作原理。 Javascript的当前线程启动异步操作。然后,该异步操作由其他一些本机代码管理。然后,Javascript的当前线程将运行至完成并完成(从而清除堆栈)。

一段时间后,运行异步操作的本机代码会看到操作已完成,并将事件发布到Javascript事件队列以调用该异步操作的回调。当JS引擎没有运行任何其他东西时,它会将该事件从队列中拉出并处理它(调用回调)。在它调用回调时,它将有一个空的堆栈帧。

回调函数将有一个活动的范围对象,但在Javascript范围内与堆栈框架完全分开。

唯一一次这可能是一个问题,如果您的回调曾被同步调用过。然后,显然会出现堆栈堆积和堆栈溢出的可能性。但是,只要回调总是异步调用(它应该是),那么就没有问题。

  

有没有办法重构这段代码不能递归?

这是一个非常有用的设计模式,在Javascript异步编程中,从上一次迭代完成后运行下一次迭代,并从中调用函数是通常的方法。没有理由重构它。

答案 1 :(得分:2)

不,这不会导致堆栈溢出。当您调用异步函数时,原始函数返回,因此它的堆栈帧被释放。回调函数是从事件处理程序调用的,而不是从原始函数调用的。