async = require('async');
var documents = ['a', 'b', 'c', 'd', 'e', 'f'];
async.forEachLimit(documents, 2, function(item, callback) {
console.log(".", item);
callback(null);
}, function(err){
console.log("end", err);
});
Protokoll
$ node test.js
. a
. a
. a
. a
. a
. a
end undefined
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
. b
[...]
node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
RangeError: Maximum call stack size exceeded
forEachLimit
sieht falsch aus.
started += 1
running += 1
sollte vor den Iteratoraufruf verschoben werden. arr[started]
sollte auch in arr[started - 1]
geändert werden
Hinweis: Sie werden auf diesen Fehler nur stoßen, wenn Code innerhalb von iterator iterator den Callback im selben Tick aufruft.
STOPPEN Sie den Aufruf von SYNC-Funktionen in async.js
Ich bin auf dieses Problem gestoßen, als ich in meinem Iterator ein bedingtes return callback(null);
hatte. Es bedeutete, dass ich das Klügere tun musste, nämlich das Array mit Array.filter
zu filtern, bevor ich async.forEach
anwendete, also war es tatsächlich irgendwie hilfreich ...
Wenn Sie _wirklich_ glauben, dass Sie dies tun sollten, können Sie dies umgehen, indem Sie process.nextTick(function() { callback(); })
verwenden.
@jacobrask Das hat gut funktioniert. Danke
Das Ausführen callback(null);
ist synchron. Sie müssen es asynchron aufrufen, ala process.nextTick(callback)
oder process.nextTick(function() { callback(null); });
. Wie @bobrik sagte, hören Sie auf, Synchronisierungsfunktionen asynchron aufzurufen :)
Zu sagen, „Stoppen Sie das Aufrufen von Synchronisierungsfunktionen in Async“, verfehlt den Punkt – es ist kaputt, und nur in forEachLimit scheint dies ein Problem zu sein.
async.forEachLimit(['a','b'], 1, function(item, callback){
if(something) {
doStuff(function(){ callback(); });
} else {
callback();
}
});
Während ich mich ziemlich einfach vor diesem sehr spezifischen Beispiel schützen kann (wie @jacobrask durch Filtern erwähnt), was ist, wenn doStuff() (das sich möglicherweise in einer Bibliothek außerhalb meiner Kontrolle befindet) beschließt, meinen Rückruf ohne process.nextTick() aufzurufen?
Ich habe Code hinzugefügt, um async.nextTick aufzurufen, wenn ein synchroner Iterator erkannt wird, der in diesen Fällen einen Stapelüberlauf vermeiden sollte. Aber im Ernst, HÖREN SIE AUF, SYNC-FUNKTIONEN IN ASYNC AUFZURUFEN! ... machen Sie Ihre Funktionen stattdessen konsistent synchron oder konsistent asynchron ;)
Das ist mir auch mit async.eachSeries
passiert.
Passiert auch in mapLimit
, und ja, meine Funktion ist sync, weil es eine Scheinfunktion ist. Dann wickle ich es in setImmediate
ein, das Problem ist gelöst.
Passieren Sie mit mir auf async.forEachOfLimit
Stehe vor dem gleichen Problem mit async.waterfall
.
async.queue natürlich auch.
Ich habe einen Synchronisierungsvorgang durchgeführt. Ich habe es behoben, indem ich geändert habe von:
callback();
zu
setTimeout(callback, 0);
Das ist mir passiert, als ich einen Haken an einem Versprechen hatte. Etwas wie:
async.forEach(items, (item:any, callback:Function) => {
someAsyncPromise(item).then(() => {
callback();
}).catch((err) => {
//console error or something here
callback();
})
});
catch muss vor dem async-Bit in Promise ausgelöst werden, da dieser Fehler nur ausgelöst wird, wenn eine Ausnahme in Promise aufgetreten ist.
`
Ich verstehe, dass wir aufhören sollten, Synchronisierungsfunktionen asynchron aufzurufen.
Aber wenn der Aufruf der Sync-Funktion callback() innerhalb des Async-Bodys falsch ist, warum zeigt die Async-Dokumentation das in den Beispielen?
Kann mir jemand helfen zu verstehen, wie man stattdessen mit dem async-Modul „richtig“ arbeitet?
Hier ist ein Beispiel direkt aus der Async-Dokumentation:
// assuming openFiles is an array of file names
async.each(openFiles, function(file, callback) {
// Perform operation on file here.
console.log('Processing file ' + file);
if( file.length > 32 ) {
console.log('This file name is too long');
callback('File name too long');
} else {
// Do work to process file here
console.log('File processed');
callback();
}
}, function(err) {
// if any of the file processing produced an error, err would equal that error
if( err ) {
// One of the iterations produced an error.
// All processing will now stop.
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
}
});
https://caolan.github.io/async/docs.html#each
Danke!
Hilfreichster Kommentar
Ich habe einen Synchronisierungsvorgang durchgeführt. Ich habe es behoben, indem ich geändert habe von:
zu