Powinieneś zawinąć wywołanie funkcji rekurencyjnej w plik
setTimeout
,
setImmediate
lub
process.nextTick
funkcja, aby dać node.js szansę na wyczyszczenie stosu. Jeśli tego nie zrobisz i istnieje wiele pętli bez prawdziwego wywołania funkcji asynchronicznej lub jeśli nie będziesz czekać na wywołanie zwrotne, RangeError: Maximum call stack size exceeded
będzie to nieuniknione .
Istnieje wiele artykułów dotyczących „Potencjalnej pętli asynchronicznej”. Oto jeden .
Teraz trochę więcej przykładowego kodu:
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() {
...
});
To prawda:
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() {
...
});
Teraz Twoja pętla może stać się zbyt wolna, ponieważ tracimy trochę czasu (jedna podróż w obie strony przeglądarki) na rundę. Ale nie musisz sprawdzać setTimeout
w każdej rundzie. Zwykle można to robić co tysięczny raz. Ale może się to różnić w zależności od rozmiaru twojego stosu:
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() {
...
});