Debes envolver tu llamada de función recursiva en un
setTimeout
,
setImmediate
o
process.nextTick
función para darle a node.js la oportunidad de borrar la pila. Si no hace eso y hay muchos bucles sin ninguna llamada de función asíncrona real o si no espera la devolución de llamada, RangeError: Maximum call stack size exceeded
será inevitable .
Hay muchos artículos sobre el "bucle asincrónico potencial". Aquí tienes uno .
Ahora un código de ejemplo más:
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() {
...
});
Esto es correcto:
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() {
...
});
Ahora su ciclo puede volverse demasiado lento, porque perdemos un poco de tiempo (un viaje de ida y vuelta al navegador) por ronda. Pero no tiene que llamar setTimeout
en todas las rondas. Normalmente está bien hacerlo cada milésima vez. Pero esto puede diferir según el tamaño de su pila:
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() {
...
});