Angenommen, Sie verwalten eine Bibliothek, die eine Funktion verfügbar macht getData
. Ihre Benutzer rufen es auf, um aktuelle Daten abzurufen:
var output = getData();
Unter der Haube werden Daten in einer Datei gespeichert, sodass Sie sie getData
mit Node.js integriert implementieren fs.readFileSync
. Es ist beides offensichtlich getData
und fs.readFileSync
es handelt sich um Synchronisierungsfunktionen. Eines Tages wurde Ihnen gesagt, dass Sie die zugrunde liegende Datenquelle auf ein Repo wie MongoDB umstellen sollen, auf das nur asynchron zugegriffen werden kann. Sie wurden auch angewiesen, Ihre Benutzer getData
nicht zu verärgern. Die API kann nicht geändert werden, um lediglich ein Versprechen zurückzugeben oder einen Rückrufparameter zu fordern. Wie erfüllen Sie beide Anforderungen?
Asynchrone Funktion mit Rückruf / Versprechen ist die DNA von JavasSript und Node.js. Jede nicht triviale JS-App ist wahrscheinlich von diesem Codierungsstil durchdrungen. Diese Praxis kann jedoch leicht zu einer sogenannten Rückrufpyramide des Untergangs führen. Schlimmer noch, wenn ein Code in einem Aufrufer in der Aufrufkette vom Ergebnis der asynchronen Funktion abhängt, muss dieser Code ebenfalls in die Rückruffunktion eingeschlossen werden, wodurch dem Anrufer eine Einschränkung des Codierungsstils auferlegt wird. Von Zeit zu Zeit muss eine asynchrone Funktion (die häufig in einer Bibliothek eines Drittanbieters bereitgestellt wird) in eine Synchronisierungsfunktion eingekapselt werden, um ein massives globales Re-Factoring zu vermeiden. Die Suche nach einer Lösung zu diesem Thema endete normalerweise mit Node Fibersoder davon abgeleitete npm-Pakete. Aber Fasern können das Problem, mit dem ich konfrontiert bin, einfach nicht lösen. Sogar das Beispiel des Autors von Fibers illustrierte den Mangel:
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
Tatsächliche Ausgabe:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
Wenn die Funktion Fibre den asynchronen Funktionsschlaf wirklich synchronisiert, sollte die Ausgabe wie folgt lauten:
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
Ich habe ein weiteres einfaches Beispiel in JSFiddle erstellt und nach Code gesucht, um die erwartete Ausgabe zu erzielen. Ich akzeptiere eine Lösung, die nur in Node.js funktioniert, sodass Sie jedes npm-Paket benötigen können, obwohl Sie nicht in JSFiddle arbeiten.
Antworten:
deasync verwandelt die asynchrone Funktion in eine Synchronisierung, die mit einem Blockierungsmechanismus implementiert wird, indem die Ereignisschleife Node.js auf JavaScript-Ebene aufgerufen wird. Infolgedessen blockiert Deasync nur die Ausführung von nachfolgendem Code, ohne den gesamten Thread zu blockieren oder zu warten. Mit diesem Modul finden Sie hier die Antwort auf die jsFiddle-Herausforderung:
(Haftungsausschluss: Ich bin Mitautor von
deasync
. Das Modul wurde nach dem Posten dieser Frage erstellt und hat keinen praktikablen Vorschlag gefunden.)quelle
function AnticipatedSyncFunction(){ var ret; setTimeout(function(){ var startdate = new Date() //console.log(startdate) ret = "hello" + startdate; },3000); while(ret === undefined) { require('deasync').runLoopOnce(); } return ret; } var output = AnticipatedSyncFunction(); var startdate = new Date() console.log(startdate) console.log("output="+output);
und ich erwarte 3 Sekunden Unterschied in der Datumsausgabe!Es gibt auch ein npm-Synchronisationsmodul. Hiermit wird der Prozess der Ausführung der Abfrage synchronisiert.
Wenn Sie parallele Abfragen synchron ausführen möchten, beschränken Sie sich darauf, da der Knoten niemals auf eine Antwort wartet. Das Synchronisationsmodul eignet sich perfekt für diese Art von Lösung.
Beispielcode
Referenzlink: https://www.npmjs.com/package/sync
quelle
Ja. Innerhalb der Faser wartet die Funktion vor der Protokollierung
ok
. Glasfasern machen asynchrone Funktionen nicht synchron, ermöglichen jedoch das Schreiben von synchron aussehendem Code, der asynchrone Funktionen verwendet und dann innerhalb von a asynchron ausgeführt wirdFiber
.Du kannst nicht. Es ist unmöglich, asynchronen Code synchron zu machen. Sie müssen dies in Ihrem globalen Code antizipieren und von Anfang an asynchron schreiben. Ob Sie den globalen Code in eine Glasfaser einwickeln, Versprechen, Versprechengeneratoren oder einfache Rückrufe verwenden, hängt von Ihren Vorlieben ab.
Das können sowohl Versprechen als auch Fasern.
quelle
fs
Methoden verwenden würden.Sie müssen Versprechen verwenden:
Ich mag Pfeilfunktionsdefinitionen mehr. Jede Zeichenfolge der Form "() => {...}" kann aber auch als "function () {...}" geschrieben werden.
TopDog ist also nicht asynchron, obwohl eine asynchrone Funktion aufgerufen wird.
BEARBEITEN: Mir ist klar, dass Sie häufig eine asynchrone Funktion in eine Synchronisierungsfunktion einbinden müssen. Für diese Situationen ist hier ein Partytrick:
Wenn Sie dies mit Rückrufen verwenden, können Sie einen Wrap durchführen, der keine Versprechen verwendet:
Wenn Sie diesen Trick auf einen EventEmitter anwenden, können Sie dieselben Ergebnisse erzielen. Definieren Sie den Listener des EventEmitter, in dem ich den Rückruf definiert habe, und geben Sie das Ereignis aus, in dem ich den Rückruf aufgerufen habe.
quelle
Ich kann kein Szenario finden, das nicht mit Knotenfasern gelöst werden kann. Das Beispiel, das Sie mit Node-Fibers bereitgestellt haben, verhält sich wie erwartet. Der Schlüssel besteht darin, den gesamten relevanten Code in einer Faser auszuführen, damit Sie keine neue Faser an zufälligen Positionen starten müssen.
Sehen wir uns ein Beispiel an: Angenommen, Sie verwenden ein Framework, das der Einstiegspunkt Ihrer Anwendung ist (Sie können dieses Framework nicht ändern). Dieses Framework lädt die nodejs-Module als Plugins und ruft einige Methoden für die Plugins auf. Nehmen wir an, dieses Framework akzeptiert nur synchrone Funktionen und verwendet keine Fasern für sich.
Es gibt eine Bibliothek, die Sie in einem Ihrer Plugins verwenden möchten, aber diese Bibliothek ist asynchron und Sie möchten sie auch nicht ändern.
Der Haupt-Thread kann nicht ausgegeben werden, wenn keine Faser läuft, aber Sie können trotzdem Plugins mit Fasern erstellen! Erstellen Sie einfach einen Wrapper-Eintrag, der das gesamte Framework innerhalb einer Glasfaser startet, damit Sie die Ausführung über die Plugins erzielen können.
Nachteil: Wenn das Framework intern verwendet
setTimeout
oder verwendetPromise
, entgeht es dem Glasfaserkontext. Dies kann durch spöttisch umgingen werdensetTimeout
,Promise.then
und alle Event - Handler.Auf diese Weise können Sie eine Faser erhalten, bis a
Promise
aufgelöst ist. Dieser Code übernimmt eine asynchrone Funktion (Promise Returning) und setzt die Glasfaser fort, wenn das Versprechen aufgelöst wird:Framework-entry.js
async-lib.js
my-plugin.js
my-entry.js
Wenn Sie ausführen
node framework-entry.js
, wird ein Fehler ausgegeben :Error: yield() called with no fiber running
. Wenn Sie es ausführennode my-entry.js
, funktioniert es wie erwartet.quelle
Die Synchronisierung des Node.js-Codes ist in einigen Aspekten wie der Datenbank von entscheidender Bedeutung. Der eigentliche Vorteil von Node.js liegt jedoch im asynchronen Code. Da es sich um einen einzelnen Thread handelt, der nicht blockiert.
Wir können es mit wichtigen Funktionen synchronisieren. Fibre () Verwenden Sie await () und defer (). Wir rufen alle Methoden mit await () auf. Ersetzen Sie dann die Rückruffunktionen durch defer ().
Normaler Async-Code. Hierbei werden CallBack-Funktionen verwendet.
Synchronisieren Sie den obigen Code mit Fibre (), wait () und defer ()
Ich hoffe das wird helfen. Danke
quelle
Heutzutage kann dieses Generatormuster in vielen Situationen eine Lösung sein.
Hier ein Beispiel für sequentielle Konsolenaufforderungen in nodejs mit der asynchronen Funktion readline.question:
quelle
Sie sollten nicht darauf achten, was um den Anruf herum passiert , der die Faser erzeugt, sondern darauf, was innerhalb der Faser passiert . Sobald Sie sich in der Glasfaser befinden, können Sie synchron synchronisieren. Beispielsweise:
Innerhalb der Glasfaser, die Sie anrufen
f1
,f2
undsleep
als ob sie synchron wären.In einer typischen Webanwendung erstellen Sie die Glasfaser in Ihrem HTTP-Anforderungs-Dispatcher. Sobald Sie dies getan haben, können Sie Ihre gesamte Anforderungsbearbeitungslogik im Synchronisierungsstil schreiben, auch wenn sie asynchrone Funktionen (fs, Datenbanken usw.) aufruft.
quelle
while(true) handleNextRequest()
Schleife haben. Das Einwickeln jedes Anforderungshandlers in eine Faser würde.Ich hatte zuerst mit node.js zu kämpfen, und async.js ist die beste Bibliothek, die ich gefunden habe, um Ihnen dabei zu helfen. Wenn Sie synchronen Code mit dem Knoten schreiben möchten, gehen Sie wie folgt vor.
Dieses Programm wird IMMER Folgendes produzieren ...
quelle
async
funktioniert in deinem Beispiel b / c es istmain
, was Anrufer nicht interessiert. Stellen Sie sich vor, Ihr gesamter Code ist in eine Funktion eingeschlossen, die das Ergebnis eines Ihrer asynchronen Funktionsaufrufe zurückgeben soll. Es kann leicht durch Hinzufügenconsole.log('return');
am Ende Ihres Codes überprüft werden, ob es nicht funktioniert . In diesem Fall erfolgt die Ausgabe vonreturn
nach,in main
aber vorherstep 1
.Javascript ist eine einzelne Thread-Sprache, Sie möchten nicht Ihren gesamten Server blockieren! Async-Code eliminiert Rennbedingungen, indem Abhängigkeiten explizit gemacht werden.
Lernen Sie, asynchronen Code zu lieben!
Suchen Sie
promises
nach asynchronem Code, ohne eine Pyramide der Rückrufhölle zu erstellen. Ich empfehle die VersprechenQ-Bibliothek für node.js.http://howtonode.org/promises
BEARBEITEN: Dies ist bei weitem meine umstrittenste Antwort. Der Knoten verfügt jetzt über ein Schlüsselwort für den Ertrag, mit dem Sie asynchronen Code so behandeln können, als wäre er synchron. http://blog.alexmaccaw.com/how-yield-will-transform-node
quelle