JavaScript Async-Iteratoren und Generatoren
JavaScript async-Iteratoren und async-Generatoren: Symbol.asyncIterator, async function*, for await...of und lazy paginiertes Fetch mit ausführbarem Code.
Asynchrone Programmierung ist ein Grundpfeiler der modernen JavaScript-Entwicklung und ermöglicht es Entwicklern, nicht-blockierenden, nebenläufigen Code zu schreiben, der Aufgaben wie Netzwerkanfragen, Datei-I/O und Timer effizient verarbeiten kann. Dieser Leitfaden behandelt async-Iteratoren und async-Generatoren — zwei in ECMAScript 2018 eingeführte Features, mit denen sich über Daten iterieren lässt, die nach und nach eintreffen: ein Chunk pro Netzwerk-Roundtrip, ein Ereignis pro Benutzeraktion — ohne den Rest des Programms zu blockieren.
Diese Seite setzt voraus, dass Sie mit regulären Iterables, Generatoren und Promises vertraut sind. Falls eines davon neu für Sie ist, lesen Sie es bitte zuerst.
Async-Iteratoren verstehen
Was sind Async-Iteratoren?
Async-Iteratoren sind eine spezielle Art von Iterator, die für die Verarbeitung asynchroner Datenströme ausgelegt ist. Im Gegensatz zu herkömmlichen Iteratoren, die synchron arbeiten, ermöglichen Async-Iteratoren das Iterieren über Sequenzen asynchroner Werte — etwa Promises oder Streams — auf nicht-blockierende Weise.
Technisch gilt ein object als async-iterable, wenn es die Methode Symbol.asyncIterator implementiert, die ein Async-Iterator-object zurückgibt. Hier ist ein praktisches Beispiel für die manuelle Implementierung dieses Interfaces an einem eigenen object:
Sync-Iteratoren vs. Async-Iteratoren
Der Unterschied zwischen einem regulären Iterable und einem async-Iterable lässt sich auf drei Punkte reduzieren: den Methodennamen, den Rückgabetyp von next() und die Schleife, mit der es konsumiert wird.
| Sync-Iterable | Async-Iterable | |
|---|---|---|
| Methode | Symbol.iterator | Symbol.asyncIterator |
next() gibt zurück | { value, done } | ein Promise von { value, done } |
| Konsumierende Schleife | for...of | for await...of |
| Generator-Syntax | function* | async function* |
Da next() im asynchronen Fall ein Promise zurückgibt, kann jeder Schritt der Schleife auf eine asynchrone Operation warten — einen Fetch, einen Timer, einen Datenbanklesezugriff — bevor der nächste Wert erzeugt wird. Ein gewöhnliches for...of kann das nicht: Es erwartet, dass value/done sofort verfügbar sind. Die Verwendung von for await...of auf einem rein synchronen Iterable funktioniert dennoch (die Engine verpackt die Werte in aufgelöste Promises), aber ein synchrones for...of auf einem async-Iterable funktioniert nicht — es würde lediglich über ausstehende Promise-objects iterieren.
Async-Iteratoren verwenden
Um Async-Iteratoren in Ihrem JavaScript-Code nutzen zu können, müssen Sie zunächst deren grundlegende Konzepte und Syntax verstehen. Betrachten wir ein einfaches Beispiel, das zeigt, wie Async-Iteratoren in der Praxis funktionieren:
In diesem Beispiel definieren wir eine async-Generatorfunktion generateNumbers(), die eine Folge von Zahlen asynchron liefert. Anschließend erstellen wir ein async-Iterable aus der Generatorfunktion und verwenden eine for await...of-Schleife, um über die vom Async-Iterator erzeugten Werte zu iterieren.
Hinweis: Wenn Sie innerhalb einer async function* einen einfachen Wert mit yield zurückgeben, gibt die Methode next() des Iterators automatisch ein Promise zurück, das zu { value: <Ihr Wert>, done: false } aufgelöst wird. Sie müssen ein Promise nur dann explizit mit yield zurückgeben, wenn der Konsument ein Promise-object erhalten soll und nicht den aufgelösten Wert.
Praxisanwendungen von Async-Iteratoren
Async-Iteratoren kommen häufig in Szenarien zum Einsatz, die asynchrone Datenverarbeitung beinhalten — etwa beim Abrufen von Daten aus externen APIs, beim Lesen aus Streams oder beim Verarbeiten asynchroner Ereignisse. Ihre Vielseitigkeit und Effizienz machen sie zu unverzichtbaren Werkzeugen für moderne JavaScript-Entwickler, die skalierbare und reaktionsfähige Anwendungen schreiben möchten.
JavaScript-Generatoren erkunden
Einführung in Generatoren
Generatoren sind ein leistungsstarkes, in ECMAScript 2015 eingeführtes Feature, das die Erstellung iterierbarer Sequenzen mit benutzerdefinierter Iterationslogik ermöglicht. Im Gegensatz zu herkömmlichen Funktionen, die bei Aufruf bis zur Fertigstellung ausgeführt werden, können Generatoren ihre Ausführung pausieren und fortsetzen, was eine verzögerte Auswertung von Werten ermöglicht.
Es ist wichtig, zwischen Standard-Generatoren und async-Generatoren zu unterscheiden:
- Standard-Generatoren (
function*): Liefern Werte synchron. - Async-Generatoren (
async function*): Geben bei jedemnext()-Aufruf ein Promise zurück, sodass der Konsument mitfor await...ofauf jeden Wert warten kann.
Generatoren für asynchrone Programmierung nutzen
Einer der überzeugendsten Anwendungsfälle für Generatoren ist die asynchrone Programmierung. Durch die Kombination von Generatoren und Promises können Entwickler asynchrone Arbeitsabläufe erstellen, die sowohl elegant als auch leicht nachvollziehbar sind. Hier ist ein modernes Beispiel für die Verwendung eines async-Generators zum Abrufen und Zurückgeben von Daten von einem Remote-Server:
In diesem Beispiel definieren wir eine async-Generatorfunktion fetchTodos(), die mithilfe der Funktion fetch() asynchron Daten von einer Remote-API abruft. Durch die Verwendung von await im Generator und das einzelne Zurückgeben von Elementen können wir die Ergebnisse direkt in eine for await...of-Schleife streamen, ohne manuelle .next()-Aufrufe oder Promise-Verkettung.
Paginiertes Fetch mit einem Async-Generator
Das Muster, bei dem async-Generatoren besonders glänzen, ist lazy Pagination. Viele APIs liefern Ergebnisse seitenweise und erwarten, dass die nächste Seite so lange angefordert wird, bis keine mehr vorhanden sind. Ein async-Generator kann all diese Verwaltungsarbeit verbergen: Er ruft eine Seite ab, liefert ihre Elemente einzeln und fordert die nächste Seite erst dann an, wenn der Konsument weitere Daten benötigt. Der Aufrufer kann frühzeitig abbrechen — beispielsweise wenn er das Gesuchte gefunden hat — und es werden keine weiteren Netzwerkanfragen gestellt.
Beachten Sie das break: Da der Generator lazy ist, bedeutet ein Verlassen der Schleife nach 25 Elementen, dass der Generator Seite 3 nie anfordert. Das ist der Unterschied zwischen einem async-Generator und dem Vorababrufen aller Daten in ein array — Sie zahlen nur für die Daten, die Sie tatsächlich verwenden.
Fortgeschrittene Generator-Muster
Generatoren bieten eine Vielzahl fortgeschrittener Muster und Techniken zur Lösung komplexer Programmierprobleme. Hier sind einige Beispiele, die ihre Vielseitigkeit verdeutlichen:
- Parallele Ausführung: Durch das Starten mehrerer Generatoren und das gleichzeitige Verwalten ihrer Promises können mehrere asynchrone Aufgaben gleichzeitig ausgeführt werden.
- Fehlerbehandlung: Verwenden Sie
try-catch-Blöcke innerhalb von Generatoren, um abgelehnte Promises, die während des Iterationsprozesses auftreten, elegant zu behandeln. - Datenpipelines: Erstellen Sie Datenverarbeitungspipelines durch Verkettung von Generatoren, bei denen die Ausgabe eines Generators als Eingabe für den nächsten dient.
Fazit
Zusammenfassend lässt sich sagen: Async-Iteratoren und Generatoren sind unverzichtbare Werkzeuge im Arsenal des modernen JavaScript-Entwicklers. Indem Sie diese leistungsstarken Features meistern, erschließen Sie neue Dimensionen von Ausdrucksstärke und Effizienz in Ihrem asynchronen Code. Ob Sie Webanwendungen, serverseitige APIs oder Befehlszeilen-Werkzeuge entwickeln — Async-Iteratoren und Generatoren ermöglichen es Ihnen, komplexe asynchrone Herausforderungen mit Leichtigkeit zu bewältigen. Beginnen Sie noch heute, Async-Iteratoren und Generatoren in Ihre JavaScript-Projekte einzubinden und heben Sie Ihre Programmierfähigkeiten auf ein neues Niveau!
Verwandte Themen
- Iterables — das synchrone Fundament hinter
for...ofundSymbol.iterator. - Generatoren — die
function*-Syntax, auf der async-Generatoren aufbauen. - Promises — was jedes
awaitinnerhalb eines async-Generators auflöst. - Async/await — die Syntax, mit der
for await...ofzusammenarbeitet.