Node.js: Die beste Möglichkeit, mehrere asynchrone Operationen auszuführen, und dann etwas anderes tun?

7

Im folgenden Code versuche ich, mehrere (etwa 10) HTTP-Anfragen und RSS-Parser auf einmal zu erstellen.

Ich verwende das Standard-Konstrukt forEach für ein Array von URIs, auf die ich zugreifen und das Ergebnis von. parsen muss.

Code:

%Vor%

Ich verstehe, dass wenn ich eine Funktion einmal anrufe, ich einen Rückruf verwenden sollte. Die einzige Möglichkeit, einen Callback in diesem Beispiel zu verwenden, besteht jedoch darin, eine Funktion aufzurufen, die zählt, wie oft sie aufgerufen wurde, und nur fortfährt, wenn sie so oft aufgerufen wurde wie feedsToFetch.length , was hacky aussieht .

Also meine Frage ist, was ist der beste Weg, um diese Art von Situation in node.js zu behandeln.

Vorzugsweise ohne jegliche Form von Blockierung! (Ich will immer noch diese blitzschnelle Geschwindigkeit). Ist es Versprechen oder etwas anderes?

Danke, Danny

    
DanTonyBrown 09.10.2014, 00:46
quelle

3 Antworten

9

HACKFREIE LÖSUNG

Versprechen, in die nächste JavaScript-Version aufgenommen zu werden

Die populären Promise-Bibliotheken geben Ihnen eine .all() -Methode für diesen exakten Anwendungsfall (warten auf eine Reihe von asynchronen Aufrufen, um sie abzuschließen und dann etwas anderes zu tun). Es ist die perfekte Ergänzung für Ihr Szenario

Bluebird hat auch .map() , das ein Array von Werten annehmen und damit eine Promise-Kette starten kann.

Hier ist ein Beispiel mit Bluebird .map() :

%Vor%

Beachten Sie auch, dass Sie hier keine Closure verwenden müssen, um die Ergebnisse zu akkumulieren.

Die Bluebird API Docs sind wirklich gut geschrieben, mit vielen Beispielen, so ist es macht es einfacher, aufzuheben.

Sobald ich Promise-Muster gelernt hatte, machte es das Leben so viel einfacher. Ich kann es nicht genug empfehlen.

Auch hier ist ein toller Artikel über verschiedene Ansätze zum Umgang mit asynchronen Funktionen mithilfe von Versprechungen, dem async -Modul und anderen

Hoffe, das hilft!

    
aarosil 09.10.2014, 01:54
quelle
9

Keine Hacks notwendig

Ich würde empfehlen, das asynchrone Modul zu verwenden, da es diese Art von Dingen viel einfacher macht.

async stellt async.eachSeries als asynchronen Ersatz für arr.forEach bereit und ermöglicht dies Übergeben Sie eine done Callback-Funktion, wenn sie abgeschlossen ist. Es verarbeitet alle Elemente in einer Serie, genau wie forEach . Außerdem werden Fehler in Ihrem Callback bequem verteilt, so dass Sie in der Schleife keine Handler-Logik haben müssen. Wenn Sie eine parallele Verarbeitung wünschen / benötigen, können Sie async.each verwenden.

Zwischen dem Aufruf async.eachSeries und dem Callback wird no blocking sein.

%Vor%

Alternativ können Sie ein Array von asynchronen Operationen erstellen und an async.series übergeben. Series verarbeitet Ihre Ergebnisse in einer Serie (nicht parallel) und ruft den Callback auf, wenn jede Funktion abgeschlossen ist. Der einzige Grund, dies über async.eachSeries zu verwenden, wäre, wenn Sie die vertraute arr.forEach -Syntax bevorzugen würden.

%Vor%

Oder Sie können Roll Your Own ™

Vielleicht fühlen Sie sich besonders ehrgeizig oder vielleicht möchten Sie sich nicht auf die Abhängigkeit async verlassen. Vielleicht bist du nur gelangweilt wie ich war. Wie auch immer, ich habe absichtlich die API von async.eachSeries kopiert, um zu verstehen, wie das funktioniert.

Sobald wir die Kommentare hier entfernt haben, haben wir nur 9 Codezeilen , die für beliebige -Arrays wiederverwendet werden können, die wir asynchron verarbeiten möchten! Es wird nicht das ursprüngliche Array ändern, Fehler können zum "Kurzschluss" der Iteration gesendet werden, und ein separater Rückruf kann verwendet werden. Es wird auch auf leeren Arrays funktionieren. Ziemlich viel Funktionalität für nur 9 Zeilen:)

%Vor%

Erstellen wir nun eine asynchrone Beispiel-Funktion, um damit zu arbeiten. Wir werden hier die Verzögerung mit einem setTimeout von 500 ms vortäuschen.

%Vor%

Ok, mal sehen, wie sie funktionieren!

%Vor%

Ausgabe (500 ms Verzögerung vor jedem Ausgang)

%Vor%     
user633183 09.10.2014 01:53
quelle
1

Die Verwendung einer Kopie der Liste der URL als Warteschlange zur Verfolgung der Ankunft macht es einfach:  (alle Änderungen kommentiert)

%Vor%

am Ende ist das nicht so viel "dreckiger" als Versprechen, und bietet Ihnen die Chance, unfertige URLs neu zu laden (ein Counter alleine wird Ihnen nicht sagen, welche (s) fehlgeschlagen ist). Für diese einfache parallele Download-Aufgabe wird es tatsächlich mehr Code zu Ihren Projekt-Implementierungen als eine einfache Warteschlange hinzufügen, und Promise.all () ist nicht der intuitivste Ort, um darüber zu stolpern. Sobald Sie Sub-Sub-Abfragen erhalten oder eine bessere Fehlerbehandlung als ein Zugwrack wünschen, empfehle ich dringend, Promises zu verwenden, aber Sie brauchen keinen Raketenwerfer, um ein Eichhörnchen zu töten ...

    
dandavis 09.10.2014 01:16
quelle

Tags und Links