Вы должны заключить рекурсивный вызов функции в
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
в каждом раунде. Обычно это нормально делать это каждые 1000 раз. Но это может отличаться в зависимости от размера вашего стека:
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() {
...
});