Ich möchte eine Seite erstellen, auf der einige Daten aus einer Datenbank angezeigt werden. Daher habe ich einige Funktionen erstellt, die diese Daten aus meiner Datenbank abrufen. Ich bin nur ein Neuling in Node.js. Soweit ich weiß, müsste ich sie alle verschachteln, wenn ich sie alle auf einer einzigen Seite verwenden möchte (HTTP-Antwort):
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
var html = "<h1>Demo page</h1>";
getSomeDate(client, function(someData) {
html += "<p>"+ someData +"</p>";
getSomeOtherDate(client, function(someOtherData) {
html += "<p>"+ someOtherData +"</p>";
getMoreData(client, function(moreData) {
html += "<p>"+ moreData +"</p>";
res.write(html);
res.end();
});
});
});
Wenn es viele solche Funktionen gibt, wird die Verschachtelung zu einem Problem .
Gibt es eine Möglichkeit, dies zu vermeiden? Ich denke, es hat damit zu tun, wie Sie mehrere asynchrone Funktionen kombinieren, was etwas Grundlegendes zu sein scheint.
getSomeDate
und führt dazugetSomeOtherDate
, dass der Einzug vieler Zeilen geändert wird, wodurch das Lesen des Git-Verlaufs schwieriger wird (git blame
was danach sogar nutzlos ist), und Sie machen wahrscheinlich Fehler, wenn Sie dies manuell tunAntworten:
Interessante Beobachtung. Beachten Sie, dass Sie in JavaScript normalerweise anonyme Inline-Rückruffunktionen durch benannte Funktionsvariablen ersetzen können.
Folgende:
Könnte umgeschrieben werden, um ungefähr so auszusehen:
Wenn Sie jedoch nicht vorhaben, die Rückruflogik an anderen Stellen wiederzuverwenden, ist es häufig viel einfacher, anonyme Inline-Funktionen zu lesen, wie in Ihrem Beispiel. Sie müssen auch keinen Namen für alle Rückrufe finden.
Beachten Sie außerdem, dass, wie @pst in einem Kommentar unten vermerkt, wenn Sie auf Schließungsvariablen innerhalb der inneren Funktionen zugreifen, dies keine einfache Übersetzung ist. In solchen Fällen ist die Verwendung anonymer Inline-Funktionen noch vorzuziehen.
quelle
getMoreData
verloren.someDataParser
analysiert tatsächlich ALLE Daten, da sie auch aufruftgetMoreData
. In diesem Sinne ist der Funktionsname falsch und es wird deutlich, dass wir das Verschachtelungsproblem nicht tatsächlich entfernt haben.Kay, benutze einfach eines dieser Module.
Es wird dies ändern:
Das mögen:
quelle
Zum größten Teil würde ich Daniel Vassallo zustimmen. Wenn Sie eine komplizierte und tief verschachtelte Funktion in separate benannte Funktionen aufteilen können, ist dies normalerweise eine gute Idee. In Zeiten, in denen es sinnvoll ist, dies innerhalb einer einzelnen Funktion zu tun, können Sie eine der vielen verfügbaren asynchronen Bibliotheken von node.js verwenden. Die Leute haben sich viele verschiedene Möglichkeiten ausgedacht, um dies anzugehen. Schauen Sie sich also die Modulseite von node.js an und sehen Sie, was Sie denken.
Ich habe selbst ein Modul dafür geschrieben, async.js . Mit diesem Beispiel könnte das obige Beispiel aktualisiert werden auf:
Eine schöne Sache bei diesem Ansatz ist, dass Sie Ihren Code schnell ändern können, um die Daten parallel abzurufen, indem Sie die Funktion 'series' in 'parallel' ändern. Darüber hinaus funktioniert async.js auch im Browser, sodass Sie dieselben Methoden wie in node.js verwenden können, wenn Sie auf kniffligen asynchronen Code stoßen.
Hoffe das ist nützlich!
quelle
Sie können diesen Trick mit einem Array anstelle von verschachtelten Funktionen oder einem Modul verwenden.
Weitaus augenschonender.
Sie können die Redewendung für parallele Prozesse oder sogar parallele Prozessketten erweitern:
quelle
Ich mag async.js sehr für diesen Zweck.
Das Problem wird durch den Wasserfallbefehl gelöst:
Beispiel
Die Variablen req, res werden im selben Bereich wie die Funktion (req, res) {} geteilt, die den gesamten Aufruf von async.waterfall umfasste.
Nicht nur das, Async ist sehr sauber. Was ich damit meine ist, dass ich viele Fälle wie diesen ändere:
Zum ersten:
Dann dazu:
Dann dazu:
Außerdem können viele für Async vorbereitete vorgefertigte Funktionen sehr schnell von util.js aufgerufen werden. Verketten Sie einfach, was Sie tun möchten, und stellen Sie sicher, dass o, cb universell gehandhabt wird. Dies beschleunigt den gesamten Codierungsprozess erheblich.
quelle
Was Sie brauchen, ist ein bisschen syntaktischer Zucker. Chek this out:
Ziemlich ordentlich , nicht wahr? Möglicherweise stellen Sie fest, dass HTML zu einem Array wurde. Dies liegt zum Teil daran, dass Zeichenfolgen unveränderlich sind. Daher ist es besser, wenn Sie Ihre Ausgabe in einem Array puffern, als immer größere Zeichenfolgen zu verwerfen. Der andere Grund ist wegen einer anderen schönen Syntax mit
bind
.Queue
im Beispiel ist wirklich nur ein Beispiel und kann zusammen mitpartial
wie folgt implementiert werdenquelle
last
Funktion)obj.email
und Ihre nächste Funktion verwendet sieobj.email
dann löscht sie (oder weist sie nur zunull
).Bin verliebt Async.js , seit ich es gefunden habe. Es hat eine
async.series
Funktion, mit der Sie lange Verschachtelungen vermeiden können.Dokumentation:-
Serie (Aufgaben, [Rückruf])
Führen Sie eine Reihe von Funktionen in Reihe aus, die jeweils ausgeführt werden, sobald die vorherige Funktion abgeschlossen wurde. [...]
Argumente
tasks
- Eine Reihe von Funktionen, die ausgeführt werden sollen. Jeder Funktion wird ein Rückruf übergeben, den sie nach Abschluss aufrufen muss.callback(err, [results])
- Ein optionaler Rückruf, der ausgeführt wird, sobald alle Funktionen abgeschlossen sind. Diese Funktion ruft ein Array aller Argumente ab, die an die im Array verwendeten Rückrufe übergeben wurden.So können wir es auf Ihren Beispielcode anwenden: -
quelle
Der einfachste syntaktische Zucker, den ich gesehen habe, ist Node-Promise.
npm install node-versprechen || Git-Klon https://github.com/kriszyp/node-promise
Mit dieser Option können Sie asynchrone Methoden wie folgt verketten:
Der Rückgabewert von jedem ist als Argument im nächsten verfügbar.
quelle
Was Sie dort getan haben, ist, ein Asynch-Muster zu nehmen und es auf 3 nacheinander aufgerufene Funktionen anzuwenden, von denen jede darauf wartet, dass die vorherige ausgeführt wird, bevor Sie beginnen - dh Sie haben sie synchronisiert . Der Punkt bei der Asynch-Programmierung ist, dass mehrere Funktionen gleichzeitig ausgeführt werden können und nicht auf den Abschluss warten müssen.
Wenn getSomeDate () getSomeOtherDate () nichts bietet, was getMoreData () nichts bietet, warum rufen Sie sie dann nicht asynchron auf, wie es js erlaubt, oder wenn sie voneinander abhängig (und nicht asynchron) sind, schreiben Sie sie als Einzelfunktion?
Sie müssen keine Verschachtelung verwenden, um den Fluss zu steuern. Bringen Sie beispielsweise jede Funktion zum Abschluss, indem Sie eine gemeinsame Funktion aufrufen, die feststellt, wann alle drei abgeschlossen sind, und dann die Antwort sendet.
quelle
Angenommen, Sie könnten dies tun:
Sie müssen chain () nur so implementieren, dass jede Funktion teilweise auf die nächste angewendet wird und sofort nur die erste Funktion aufgerufen wird:
quelle
Rückruf Hölle kann leicht in reinem Javascript mit Schließung vermieden werden. Bei der folgenden Lösung wird davon ausgegangen, dass alle Rückrufe der Funktionssignatur (Fehler, Daten) folgen.
quelle
Ich habe kürzlich eine einfachere Abstraktion namens wait.for erstellt , um asynchrone Funktionen im Synchronisationsmodus (basierend auf Glasfasern) aufzurufen. Es ist in einem frühen Stadium, funktioniert aber. Es ist bei:
https://github.com/luciotato/waitfor
Mit wait.for können Sie jede asynchrone Standardfunktion von nodejs aufrufen, als wäre es eine Synchronisierungsfunktion.
Verwenden von wait.for Ihr Code könnte sein:
... oder wenn Sie weniger ausführlich sein möchten (und auch Fehler hinzufügen möchten)
In allen Fällen sollten getSomeDate , getSomeOtherDate und getMoreData asynchrone Standardfunktionen sein, wobei der letzte Parameter ein Funktionsrückruf ist (err, data).
wie in:
quelle
Um dieses Problem zu lösen, habe ich nodent ( https://npmjs.org/package/nodent ) geschrieben, das Ihre JS unsichtbar vorverarbeitet. Ihr Beispielcode würde (asynchron, wirklich - lesen Sie die Dokumente) werden.
Natürlich gibt es viele andere Lösungen, aber die Vorverarbeitung hat den Vorteil, dass der Laufzeitaufwand gering oder gar nicht ist, und dank der Unterstützung der Quellzuordnung ist das Debuggen auch einfach.
quelle
Ich hatte das gleiche Problem. Ich habe gesehen, dass die Hauptbibliotheken für Knoten asynchrone Funktionen ausführen, und sie bieten eine nicht natürliche Verkettung (Sie müssen drei oder mehr Methoden confs usw. verwenden), um Ihren Code zu erstellen.
Ich habe einige Wochen damit verbracht, eine Lösung zu entwickeln, die einfach und leicht zu lesen ist. Bitte versuchen Sie es mit EnqJS . Alle Meinungen werden geschätzt.
Anstatt:
mit EnqJS:
Beachten Sie, dass der Code größer zu sein scheint als zuvor. Aber es ist nicht wie zuvor verschachtelt. Um natürlicher zu wirken, werden die Ketten sofort aufgerufen:
Und um zu sagen, dass es innerhalb der von uns aufgerufenen Funktion zurückgekehrt ist:
quelle
Ich mache es auf eine ziemlich primitive, aber effektive Weise. ZB muss ich ein Modell mit seinen Eltern und Kindern bekommen und sagen wir, ich muss separate Abfragen für sie machen:
quelle
Verwenden Sie Fibers https://github.com/laverdet/node-fibers. Dadurch sieht asynchroner Code synchron aus (ohne zu blockieren).
Ich persönlich benutze diesen kleinen Wrapper http://alexeypetrushin.github.com/synchronize Beispiel eines Codes aus meinem Projekt (jede Methode ist tatsächlich asynchron und arbeitet mit asynchroner Datei-E / A) Async-Control-Flow-Hilfsbibliotheken.
quelle
Task.js bietet Ihnen Folgendes :
An Stelle von:
quelle
Nachdem die anderen geantwortet hatten, gaben Sie an, dass Ihr Problem lokale Variablen waren. Es scheint eine einfache Möglichkeit zu sein, eine äußere Funktion zu schreiben, die diese lokalen Variablen enthält, dann eine Reihe benannter innerer Funktionen zu verwenden und namentlich darauf zuzugreifen. Auf diese Weise verschachteln Sie immer nur zwei tief, unabhängig davon, wie viele Funktionen Sie miteinander verketten müssen.
Hier ist der Versuch meines Neulings, das
mysql
Node.js-Modul mit Verschachtelung zu verwenden:Das Folgende ist ein Umschreiben unter Verwendung benannter innerer Funktionen. Die äußere Funktion
with_connection
kann auch als Halter für lokale Variablen verwendet werden. (Hier habe ich die Parameter bekamsql
,bindings
,cb
dass die Handlung in einer ähnlichen Art und Weise, aber Sie können nur einige zusätzliche lokale Variablen in definierenwith_connection
.)Ich hatte gedacht, dass es vielleicht möglich sein würde, ein Objekt mit Instanzvariablen zu erstellen und diese Instanzvariablen als Ersatz für die lokalen Variablen zu verwenden. Aber jetzt finde ich, dass der obige Ansatz mit verschachtelten Funktionen und lokalen Variablen einfacher und verständlicher ist. Es scheint einige Zeit zu dauern, OO zu verlernen, wie es scheint :-)
Hier ist meine vorherige Version mit Objekt- und Instanzvariablen.
Es stellt sich heraus, dass
bind
dies zu einem gewissen Vorteil genutzt werden kann. Es ermöglicht mir, die etwas hässlichen anonymen Funktionen, die ich erstellt habe und die nicht viel bewirkt haben, loszuwerden, außer mich selbst an einen Methodenaufruf weiterzuleiten. Ich konnte die Methode nicht direkt übergeben, da sie mit dem falschen Wert von verbunden gewesen wärethis
. Aber mitbind
kann ich den Wert angeben, denthis
ich möchte.Natürlich ist nichts davon richtig mit JS mit Node.js Codierung - ich habe nur ein paar Stunden damit verbracht. Aber vielleicht kann diese Technik mit ein wenig Polieren helfen?
quelle
async.js funktioniert dafür gut. Ich bin auf diesen sehr nützlichen Artikel gestoßen, der die Notwendigkeit und Verwendung von async.js anhand von Beispielen erklärt: http://www.sebastianseilund.com/nodejs-async-in-practice
quelle
Wenn Sie "step" oder "seq" nicht verwenden möchten, versuchen Sie es mit "line". Dies ist eine einfache Funktion, um verschachtelte asynchrone Rückrufe zu reduzieren.
https://github.com/kevin0571/node-line
quelle
C # -ähnliches Asyncawait ist eine andere Möglichkeit, dies zu tun
https://github.com/yortus/asyncawait
quelle
Mit wire würde Ihr Code folgendermaßen aussehen:
quelle
Betrachten Sie Jazz.js https://github.com/Javanile/Jazz.js/wiki/Script-showcase
quelle