2014-10-22 39 views
1

爲什麼我的瀏覽器速度變慢時,這list數據是在下面的代碼龐大:瞭解遞歸在JavaScript和替代

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. 

jsbin

我找不到一個直接的答案,從谷歌,我的問題,所以儘管得到了SO專家的幫助。我認爲它與瀏覽器內存有關,因爲我可以看到循環以很快的速度開始,並且緩慢下降並且變得沒有響應。但不知道爲什麼?

+0

遞歸函數是有限的。我多年來一直嘗試使用它們,但由於這個限制,它們在js中被折磨。限制究竟是什麼? http://stackoverflow.com/questions/2805172/what-are-the-js-recursion-limits-for-firefox-chrome-safari-ie-etc – rottenoats 2014-10-22 07:44:38

+0

@Grimbode謝謝。這看起來不錯...讓我通讀... – Shubh 2014-10-22 07:45:53

+1

@Grimbode:這不是問題在這裏。 – Cerbrus 2014-10-22 07:46:49

回答

5

JavaScript沒有尾部呼叫消除。因此,如果你循環遍歷一個列表,你會浪費大量的資源。最終你甚至可能會耗盡堆棧空間。

解決此問題的一種可能方法是異步調用尾部調用,以便在尾部調用函數開始執行之前主函數完成執行。這確保了堆棧空間不會增加:

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

請參閱以下問題了解更多詳情:

What's the difference between a continuation and a callback?


編輯:更快解決方案(如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); 
 
}

環路較爲低迷作爲其打印到在100項突發控制檯。然而它以更快的速度完成執行。

+2

嗯,我會受到傷害,我學到了一些關於JS的知識:-) – Cerbrus 2014-10-22 07:49:09

+0

*「JavaScript沒有消除尾部消息。」*我認爲你不能這樣做。只要外部觀察結果符合規格,引擎就可以進行任何優化。鑑於先進的現代發動機,我不排除尾巴呼叫消除。 – 2014-10-22 07:49:55

+1

@ T.J.Crowder現在沒有引擎擁有TCO afaik,但它是ES6的標準配置,所以它將在未來發布。 – elclanrs 2014-10-22 07:50:39

0

我建議爲此使用Javascript承諾。

function nextListItem2 (list) { 
    return new Promise(function(resolve, reject) { 
     var item = list.pop(); 
     if(item) { 
      console.log(item); 
      return nextListItem(list); 
     } else { 
      resolve(); 
     } 
    }); 
} 

nextListItem2(list);