3

当我在 Node.js 中执行以下代码时,出现以下错误:

RangeError: Maximum call stack size exceeded

这是代码:

var arr = [];
for (var i = 0; i <= 1000000; i++)
    arr.push(i);

function nextStep(index) {
    if (index === arr.length) {
        return;
    } else {
        console.log(index);
    }
    nextStep(++index);
}

nextStep(0);

我不知道发生了什么,但在 index = 17938 附近,执行终止。

使用setTimeout()帮助。这里有什么问题?

4

3 回答 3

7

您正在输入一个递归函数。这意味着在所有其他函数都返回之前,第一个函数不会返回。所以如果你有四个项目,

fn(item1)
    calls ->  fn(item2)
                  calls ->  fn(item3)
                                calls ->  fn(item4)

如您所见,嵌套不断增加。这称为堆栈。堆栈有一个最大大小,以防止无限递归和失控进程。你已经找到了它17938

这是递归的固有缺陷。它可能是一种处理任务的时尚方式,但它有其局限性。纠正它的最佳方法是改用循环:

for (var i = 0; i < arr.length; i++) {

usingsetTimeout也有效,因为该函数不是从函数本身调用的,而是使用新堆栈执行的。但是,它的性能将明显低于循环或正常的递归函数。

于 2013-11-12T18:50:32.250 回答
0

根据不同浏览器的调用堆栈,可以进行一定数量的调用。最有可能的是,您正在 Chrome 中测试您的代码,因为我相信它的调用堆栈接近 20.000。您的代码将执行该nextStep函数超过 20.000 次(100 万次),这意味着如果您的函数在达到该特定浏览器的调用堆栈限制之前不会返回某些内容,它将生成您遇到的错误。

于 2013-11-12T18:52:46.477 回答
0

在 nextStep 中调用 nextStep 会导致堆栈溢出,因为您永远不会从函数中返回(除非您找到数组的末尾,并且如果数组太大,您将永远无法到达它,直到堆栈溢出)。

一个例子:你要把所有的石头从一个地方搬到另一个地方。你的功能就像是去石头所在的地方捡起一块送到另一个地方。但是在你可以交付石头之前,你必须拿起另一个,在你可以交付之前你需要拿起另一个......很快你就携带了17938块石头。这有点重,你会被所有的石头压碎。(或者在javascript的情况下你得到一个例外)

当你使用 setTimetout 时,就像你要去那个地方,捡起一块石头,并记下你应该捡起另一块石头。然后你交付石头。之后,你查看你的笔记,发现你应该拿起石头。你可以这样做 1000000 次,因为你一次只携带一块石头。

于 2013-11-12T18:44:34.867 回答