理解javascript和替代中的递归

Shu*_*ubh 2 javascript recursion

list以下代码中的数据很大时,为什么我的浏览器会变慢:

var list = [];

/*
  Creating some huge dummy data
  Interstingly, when I change the value of i from 10000 
  to 100000, the browser hangs(becomes unresponsive)
*/
for(i=0;i<10000;i++){
  list.push(i);

}

/*Recursive function*/
var nextListItem = function() {
    var item = list.pop();

    if (item) {
        console.log(item);
        // process the list item...
        nextListItem();
    }
};
nextListItem(); // Commented this as browser becomes unresponsive.
Run Code Online (Sandbox Code Playgroud)

jsbin

我无法从谷歌找到我的问题的直接答案,所以虽然得到SO专家的帮助.我假设它与浏览器内存有关,因为我可以看到循环以很快的速度启动并慢慢减速并变得无响应.但不确定为什么?

Aad*_*hah 6

JavaScript没有尾部调用消除.因此,如果以递归方式遍历列表,则会浪费大量资源.最终你甚至可能会耗尽堆栈空间.

解决此问题的一种可能方法是异步调用尾调用,以便在尾调用函数开始执行之前main函数完成执行.这可确保堆栈空间不会增加:

var list = [];

for (var i = 0; i < 10000; i++) list.push(i);

var start = new Date;

nextListItem();

function nextListItem() {
    var item = list.pop();

    if (item) {
        console.log(item);
        setTimeout(nextListItem, 0);
    } else console.log(new Date - start);
}
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅以下问题:

延续和回调之间有什么区别?


编辑:更快的解决方案(由TJ Crowder建议):

var list = [];

for (var i = 0; i < 10000; i++) list.push(i);

var start = new Date;

nextListItem();

function nextListItem() {
    var item = list.pop();

    if (item) {
        console.log(item);
        if (item % 100) nextListItem();
        else setTimeout(nextListItem, 0);
    } else console.log(new Date - start);
}
Run Code Online (Sandbox Code Playgroud)

循环更缓慢,因为它以100个项目的突发打印到控制台.但是它可以更快地完成执行.

  • 好吧,我会被学到的,我学到了一些关于JS的东西:-) (2认同)
  • 在每个循环上执行`setTimeout`将显着降低速度,因为这是一个0-5ms的延迟(至少).相反,一个简单的循环将是最好的解决方案,或者每百(或千)次迭代等的`setTimeout`. (2认同)