Node.js Generators & Vergleichen mit Rückrufen
⚡ Intelligente Zusammenfassung
GeneratorIn Node.js sind `yield`-Funktionen, deren Ausführung bei Bedarf unterbrochen und fortgesetzt werden kann. Das Schlüsselwort `yield` pausiert die Funktion, die Methode `next` setzt sie fort, und diese Kombination vereinfacht tief verschachtelte Callback-Funktionen zu lesbarem, sequenziellem Code.

In dieser Anleitung betrachten wir Generatoren und wie sie sich von Callbacks unterscheiden.
Was sind Generatoren?
Generators wurde populär in Node.js aufgrund dessen, wozu sie fähig sind.
- Generators sind Funktionsausführungen, die angehalten und zu einem späteren Zeitpunkt fortgesetzt werden können.
- Generators sind nützlich für Konzepte wie „verzögerte Ausführung“. Indem die Ausführung angehalten und nach Belieben fortgesetzt wird, werden Werte nur dann abgerufen, wenn sie benötigt werden.
GeneratorEs gibt zwei Hauptmethoden, die im Folgenden beschrieben werden.
- Ertragsmethode — wird innerhalb einer Funktion aufgerufen, um die Ausführung genau an der Stelle anzuhalten, an der
yielderscheint. - Nächste Methode — wird von der Hauptanwendung aufgerufen, um eine Funktion fortzusetzen, die unterbrochen wurde. Die Ausführung wird bis zum nächsten Aufruf fortgesetzt.
yieldoder bis zum Ende der Funktion.
Betrachten wir ein Beispiel für die Verwendung von Generatoren. Das Beispiel definiert eine einfache Additionsfunktion, die zwei Zahlen addiert und die Ausführung an verschiedenen Stellen anhält, um das Verhalten von Generatoren zu veranschaulichen.
function* Add(x) { yield x + 1; // The value passed into the second next() call lands here var y = yield(null); return x + y; } var gen = Add(5); gen.next(); // runs to the first yield, returns { value: 6, done: false } gen.next(6); // resumes, y becomes 6, returns { value: 11, done: true }
Code Erläuterung
- Der erste Schritt besteht darin, die Generatorfunktion zu definieren. Beachten Sie die
*Um die hinzugefügtefunctionSchlüsselwort. Die Funktion wird aufgerufen.Addund nimmt einen Parameter entgegenx. - Das
yieldDas Schlüsselwort ist spezifisch für Generatoren und unterbricht die Funktion mitten in der Ausführung. Die Ausführung wird hier angehalten, bisnext()wird aufgerufen. - Der zweite
yieldDie Funktion wird sowohl angehalten als auch empfangen: der Wert, der an die folgende Funktion übergeben wird.next()Der Aufruf wird zum Wert vony. - maximal einfach anrufen
gen.next()Beim ersten Durchlauf wird die Funktion bis zum ersten ausgeführtyield. Berufunggen.next(6)setzt es fort, weist 6 zuy, und kehrt zurückx + y.
⚠️ Korrektur: Die ursprüngliche Auflistung enthielt die Zeile y = 6 gleich nach var y = yield(null);Diese Zuweisung überschreibt jeden vorhandenen Wert. next() Lieferungen, was den Zweck des Beispiels zunichtemacht und das zweite yield bedeutungslos. Der Wert wird nun übergeben durch gen.next(6)So empfängt ein Generator tatsächlich Daten vom Aufrufer.
Callbacks vs. Generatoren
GeneratorSie lösen das Problem, das als Callback-Hölle bekannt ist. Callback-Funktionen können während der Entwicklung einer Node.js-Anwendung so tief verschachtelt werden, dass sie schwer nachzuvollziehen sind.
Hier kommen Generatoren ins Spiel. Ein häufiges Beispiel ist die Erstellung von Timerfunktionen. Das folgende Beispiel erzeugt eine einfache Zeitverzögerungsfunktion und ruft diese anschließend mit Verzögerungen von 1000, 2000 und 3000 ms auf.
Schritt 1) Definiere die Callback-Funktion mit dem notwendigen Zeitverzögerungscode.
function Timedelay(ptime, callback) { setTimeout(function() { callback("Pausing for " + ptime); }, ptime); // the delay must use ptime, the parameter name }
Code Erläuterung
- Eine Funktion namens
Timedelaywird mit einem Parameter erstelltptime, das die Anzahl der Millisekunden angibt, für die pausiert werden soll. setTimeoutwartet die angegebene Anzahl Millisekunden und ruft dann die bereitgestellte Callback-Funktion auf.
⚠️ Korrektur: Der ursprüngliche Code wurde bestanden time als zweites Argument für setTimeoutaber keine Variable namens time existiert — der Parameter ist ptimeSo wie es geschrieben steht, wirft es ReferenceError: time is not defined.
Schritt 2) Betrachten wir nun den Code mit Callback-Funktionen. Um Verzögerungen von 1000, 2000 und 3000 Millisekunden zu verketten, werden die Callback-Funktionen ineinander verschachtelt.
Timedelay(1000, function(message) { console.log(message); Timedelay(2000, function(message) { console.log(message); Timedelay(3000, function(message) { console.log(message); }); }); });
Code Erläuterung
Timedelaywird als Callback mit dem Wert 1000 aufgerufen.- Innerhalb dieses Rückrufs
Timedelaywird mit 2000 erneut aufgerufen. - In diesem einen,
Timedelaywird ein drittes Mal mit 3000 aufgerufen.
⚠️ Korrektur: jeder Rückruf im ursprünglichen Protokoll msgDer Parameter heißt jedoch messageAlle drei Linien warfen ReferenceError: msg is not defined.
Aus dem obigen Code kann man sehen, dass er mit jedem zusätzlichen Aufruf unübersichtlicher wird – diese Verschachtelung ist das, was die Callback-Hölle beschreibt.
Schritt 3) Betrachten wir nun dasselbe Verhalten, geschrieben mit Generatoren. Die Sequenz wird als drei flache Zeilen anstatt als drei Verschachtelungsebenen gelesen.
function* Messages() { console.log(yield Timedelay(1000)); console.log(yield Timedelay(2000)); console.log(yield Timedelay(3000)); }
Code Erläuterung
- Es wird eine Generatorfunktion definiert, die die
TimedelayFunktion. yieldwird verwendet mitTimedelayund 1000 als Parameterwert.yieldwird erneut bei 2000 und dann noch einmal bei 3000 verwendet.
⚠️ Korrektur: der ursprüngliche Autor schrieb console,log(...) mit einem Komma anstelle eines Punktes in allen drei Zeilen, was einen Syntaxfehler darstellt und verhindert, dass die Datei überhaupt analysiert werden kann.
So führen Sie ein Generator mit einer Läuferfunktion
Der obige Generator liest sich zwar elegant, tut aber von selbst nichts. Genau dieses Detail lassen die meisten Erklärungen aus, und deshalb wirkt die einfache Version wie Zauberei. Ein Generator ist wie eine pausierte Maschine; irgendetwas muss den Knopf immer wieder drücken. Messages() Es wird lediglich ein Generatorobjekt erstellt und sofort zurückgegeben; es startet kein Timer und es wird nichts ausgegeben.
Das fehlende Puzzleteil ist ein Runner: eine kleine Funktion, die aufruft next()wartet, bis die asynchrone Arbeit abgeschlossen ist, und ruft dann auf next() und erneut das Ergebnis.
// Timedelay now hands its result back to the runner function Timedelay(ptime) { return function(resume) { setTimeout(function() { resume("Pausing for " + ptime); }, ptime); }; } // The runner drives the generator to completion function run(generatorFunction) { var it = generatorFunction(); function step(value) { var result = it.next(value); if (result.done) return; // result.value is the function returned by Timedelay result.value(step); } step(); } run(Messages);
Drei Punkte sind dafür notwendig. Erstens: Timedelay Es nimmt keine Callback-Funktion mehr direkt entgegen; stattdessen gibt es eine Funktion zurück, die der Runner aufrufen kann und die Kontrolle zurückgibt, sobald der Timer auslöst. Zweitens, it.next(value) speist das vorherige Ergebnis in den pausierten Generator ein, wodurch dies ermöglicht wird yield Auf der rechten Seite einer Aufgabe zu erscheinen. Drittens stoppt der Läufer, sobald result.done Wenn die Bedingung wahr wird, endet die Rekursion auf natürliche Weise. Dieses Runner-Muster wird von Bibliotheken wie co bereitgestellt und ist der Mechanismus, der async/await später in die Sprache selbst aufgenommen.
Generators vs. async/await: Welche Methode ist die richtige?
Generators waren die Standardmethode, um flachen asynchronen Code zu schreiben, bevor async/await Es existierte bereits, und beide basieren auf der gleichen Grundidee, eine Funktion mittendrin anzuhalten. Node unterstützt dies. async/await Seit Version 7.6 ist dies nativ möglich, was die Empfehlung für alle, die heute eine neue Aufgabe beginnen, verändert.
| Aspekt | Generatoren | async / warten |
|---|---|---|
| Läufer/in gesucht | Ja, von Ihnen oder einer Bibliothek verfasst. | Nein, es ist in die Sprache integriert. |
| Pause-Schlüsselwort | yield |
await |
| Fehlerbehandlung | Der Läufer muss Fehler weiterleiten | Gewöhnlicher Versuch und Fang |
| Kann teilweise pausieren | Ja, und kann selektiv wieder aufgenommen werden. | Nein, läuft bis zum Ende |
| am besten für | Faule Sequenzen und unendliche Ströme | Gewöhnliche asynchrone Arbeit |
Arbeiten jederzeit weiterbearbeiten können. Jede Präsentation und jeder KI-Avatar, den Sie von Grund auf neu erstellen oder hochladen, async/await Für asynchronen Ablauf in neuem Code ist dies vorteilhaft, da der Runner entfernt und die üblichen try- und catch-Blöcke wiederhergestellt werden. Generatoren sollten nur für ihre Kernaufgaben verwendet werden: das verzögerte Erzeugen von Werten, das Iterieren über große oder unendliche Sequenzen und alle Fälle, in denen der Nutzer den genauen Zeitpunkt der Berechnung des nächsten Werts bestimmt.
gemeinsam Generator Fehler und wie man sie behebt
Die meisten Generatorprobleme entstehen dadurch, dass man vergisst, dass die Funktion inaktiv ist, bis sie aufgerufen wird. next()oder durch kleine Syntaxfehler um den Stern herum. Jedes der folgenden Symptome nennt seine Ursache und seine Lösung.
- Es passiert nichts, wenn der Generator aufgerufen wird: Der Aufruf gibt einen Iterator zurück, kein Ergebnis.
next()oder übergebe den Ball an einen Läufer. - Syntaxfehler bei yield: Der Stern fehlt.
yieldist nur innerhalb eines gültigfunction*. - Der Wert von next() ist undefiniert: Der Erste
next()Der Aufruf kann keinen Wert liefern, da der Generator noch nicht erreicht hat.yieldNoch nicht. Senden Sie Daten ab dem zweiten Anruf. - Endlosschleife in einem Läufer:
result.donewird nie überprüft,next()Die Funktion wird immer wieder aufgerufen, auch nach dem Ende. Die Bedingung „Immer zurückkehren, wenn fertig“ ist wahr. - Fehler verschwinden stillschweigend: Eine Ablehnung innerhalb des asynchronen Schritts wird niemals an den Generator zurückgegeben. Leiten Sie sie weiter mit
it.throw(err)damit ein innerhalb des Generators geschriebener try-catch-Block das Problem tatsächlich erkennen und behandeln kann.




