3

When I'm am executing the following code in Node.js, I get the folliowing error:

RangeError: Maximum call stack size exceeded

This is the code:

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);

I have no clue what is happening, but near index = 17938, the execution terminates.

Using a setTimeout() helps. What could be wrong here?

sprijk
  • 281
  • 1
  • 3
  • 11

3 Answers3

7

You are entering a recursive function. This means that the first function won't return until all the other functions have returned. So if you had four items,

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

As you can see, the nesting builds up and up. This is called the stack. There is a maximum size for the stack, to prevent infinite recursion and runaway processes. You have found it with 17938.

This is an inherent flaw with recursion. It can be a stylish way to approach a task, but it has its limitations. The best way to correct it is to use a loop instead:

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

Using setTimeout also works, because the function is not called from the function itself, but is executed with a new stack. However, it will have significantly lower performance than a loop or than a normal recursive function.

lonesomeday
  • 233,373
  • 50
  • 316
  • 318
0

Calling nextStep inside nextStep causes a stack overflow since you never return from the function (unless you found the end of the array, and if the array is too big you will never reach it until the stack overflows).

An example: You are going to move all the stones from one place to another. Your function is like going to the place where the stones are and pick up one to be delivered to another place. But before you can deliver the stone, you must pick up another, and before you can deliver that you need to pick up another... and soon you are carrying 17938 stones. That is a little bit to heavy and you get crushed under all the stones. (or in the javascript case you get an exception)

When you use setTimetout it is like you are going to the place, pick up a stone, and make a note that you should pickup another stone. Then you deliver the stone. After that you look at your notes and see that you should pick up at stone. And you can do this 1000000 times since you are only carrying one stone at a time.

some
  • 48,070
  • 14
  • 77
  • 93
  • It does "return" in the end of the array, but quits already at 17938. Wouldn't it be more like memory exhaustion? Using setTimout() in here solves the problem... – sprijk Nov 12 '13 at 18:52
  • @sprijk You get an exception, not a return. You get the exception because there isn't enough room in the stack. The stack is limited, so technically it is a memory exhaustion of a specific type of memory. – some Nov 12 '13 at 18:55
0

There's a certain number of calls that can be made, based on the call stack of different browsers. Most likely, you are testing your code in Chrome, since, I believe, it has the call stack near 20.000. Your code will execute the nextStep function more than 20.000 times (1 million), which means that if your function will not return something until it reaches the call stack limit of that particular browser, it will generate the error that you are getting.

vladzam
  • 5,462
  • 6
  • 30
  • 36