您应该将递归函数调用包装到
setTimeout
,
setImmediate
要么
process.nextTick
函数使node.js有机会清除堆栈。如果您不这样做,并且有许多循环没有任何真正的异步函数调用,或者如果您不等待回调,那么您RangeError: Maximum call stack size exceeded
将不可避免。
有许多有关“潜在异步循环”的文章。这是一个。
现在再看一些示例代码:
var condition = false,
max = 1000000;
function potAsyncLoop( i, resume ) {
if( i < max ) {
if( condition ) {
someAsyncFunc( function( err, result ) {
potAsyncLoop( i+1, callback );
});
} else {
potAsyncLoop( i+1, resume );
}
} else {
resume();
}
}
potAsyncLoop( 0, function() {
...
});
这是正确的:
var condition = false,
max = 1000000;
function potAsyncLoop( i, resume ) {
if( i < max ) {
if( condition ) {
someAsyncFunc( function( err, result ) {
potAsyncLoop( i+1, callback );
});
} else {
setTimeout( function() {
potAsyncLoop( i+1, resume );
}, 0 );
}
} else {
resume();
}
}
potAsyncLoop( 0, function() {
...
});
现在您的循环可能变得太慢,因为我们每回合会浪费一点时间(一次浏览器往返)。但是您不必setTimeout
每次都跟注。通常,每千次可以这样做。但这可能会有所不同,具体取决于您的堆栈大小:
var condition = false,
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() {
...
});