簡體   English   中英

javascript中遞歸函數可計數時,最大調用堆棧大小超出RangeError

[英]Maximum call stack size exceeded RangeError when recursive function is countable in javascript

我創建了一個腳本,用於將數字除以所選的小數位數。 除非我設置了大量的小數位,否則一切都正常。 當十進制數字數組長度達到〜2400時,通過Node.js運行的文件將放棄,而Chrome則將其保留為〜1900。

我簡化了代碼,下面的腳本示例拋出了Maximum call stack size exceeded RangeError的問題, ~20000十進制數字數組長度。 我以為無限次調用循環或遞歸函數時會拋出此錯誤,但是在我的情況下,迭代次數很多。 它可能是一個巨大的數字,但我的模塊旨在對大數字進行數學運算。

為什么會發生,我可以避免發生RangeError嗎?

 var decimals = []; var max = 20000; recurse(); function recurse() { decimals.push(Math.floor(Math.random()*10)); if(decimals.length === max) return; recurse(); } 

不,可以在調用堆棧上放置多少個函數調用是有限制的,因此即使遞歸函數具有可到達的基本情況,如果遞歸調用的數量過多,它仍然會引發錯誤。

一種解決方法是使用一種稱為trampoline技術,在該技術中,您不直接在函數內部執行遞歸調用,而是插入一個新函數,然后在循環中執行該新函數,直到達到基本情況為止。

使用此技術,您的函數可以執行任意數量的遞歸調用,因為您不會同時將更多的這些函數調用放置到調用堆棧中,因此不會溢出。

 var decimals = []; var max = 20000; function _recurse(){ decimals.push(Math.floor(Math.random()*10)); if(decimals.length === max) return; return () => _recurse(); } const trampoline = fn => (...args) => { let res = fn(...args); while (typeof res === 'function') { res = res(); } return res; } const recurse = trampoline(_recurse); recurse() console.log(decimals); 

請注意,無需使用循環即可以更簡單的方式使用循環來解決問題。 例如:

 function createRandomSequence(amount) { const decimals = []; for (let i = 0; i < amount; i++) { decimals.push(Math.floor(Math.random()*10)); } return decimals; } console.log(createRandomSequence(10)); 

只需使用常規循環或類似方法即可:

 const random = length => Array.from({ length }, () => Math.floor(Math.random() * 10));

const decimals = random(20000);

關於調用堆棧:請參閱此網頁

如果您使用的是小數點后的20,000(偽隨機數),還可以使用類似以下內容的方法:

 var maxDecimals = 20000; var decimals = Array.from({length: maxDecimals}) .map(v => Math.floor(Math.random()*10)); console.log(decimals); 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM