Async: „Maximale Call-Stack-Größe überschritten“ mit async.forEachLimit

Erstellt am 26. Dez. 2011  ·  15Kommentare  ·  Quelle: caolan/async

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

Hilfreichster Kommentar

Ich habe einen Synchronisierungsvorgang durchgeführt. Ich habe es behoben, indem ich geändert habe von:

callback();

zu

setTimeout(callback, 0);

Alle 15 Kommentare

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!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen