简体   繁体   中英

Error traversing large arrays in JavaScript without timeout

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?

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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM