您应该将递归函数调用包装到
setTimeout
,setImmediate
要么process.nextTick
函数使node.js有机会清除堆栈。如果您不这样做,并且有很多循环没有任何 真正的
异步函数调用,或者如果您不等待回调,那么您
RangeError: Maximum call stack size exceeded将 不可避免 。
有很多有关“潜在异步循环”的文章。这是一个。
现在再看一些示例代码:
// ANTI-PATTERN// THIS WILL CRASHvar condition = false, // potential means "maybe never" max = 1000000;function potAsyncLoop( i, resume ) { if( i < max ) { if( condition ) { someAsyncFunc( function( err, result ) { potAsyncLoop( i+1, callback ); }); } else { // this will crash after some rounds with // "stack exceed", because control is never given back // to the browser // -> no GC and browser "dead" ... "VERY BAD" potAsyncLoop( i+1, resume ); } } else { resume(); }}potAsyncLoop( 0, function() { // pre after the loop ...});这是对的:
var condition = false, // potential means "maybe never" max = 1000000;function potAsyncLoop( i, resume ) { if( i < max ) { if( condition ) { someAsyncFunc( function( err, result ) { potAsyncLoop( i+1, callback ); }); } else { // Now the browser gets the chance to clear the stack // after every round by getting the control back. // Afterwards the loop continues setTimeout( function() { potAsyncLoop( i+1, resume ); }, 0 ); } } else { resume(); }}potAsyncLoop( 0, function() { // pre after the loop ...});现在您的循环可能变得太慢,因为我们每回合会浪费一点时间(一次浏览器往返)。但是您不必
setTimeout每次都跟注。通常,每千次可以这样做。但这可能会有所不同,具体取决于您的堆栈大小:
var condition = false, // potential means "maybe never" max = 1000000;function potAsyncLoop( i, resume ) { if( i < max ) { if( condition ) { someAsyncFunc( function( err, result ) { potAsyncLoop( i+1, callback ); }); } else { if( i % 1000 === 0 ) { setTimeout( function() { potAsyncLoop( i+1, resume ); }, 0 ); } else { potAsyncLoop( i+1, resume ); } } } else { resume(); }}potAsyncLoop( 0, function() { // pre after the loop ...});


