Signatur
Beschreibung
Ein Generator ist das Ergebnis des Aufrufs einer Generatorfunktion (definiert mit function*). Er ist gleichzeitig ein Iterator (besitzt eine next()-Methode) und ein Iterable (besitzt eine [Symbol.iterator]()-Methode, die this zurückgibt). Dadurch kann er direkt in for...of-Schleifen, Spread-Operatoren und destrukturierenden Zuweisungen verwendet werden.
Generatoren werden eingesetzt, um lazy sequences (verzögert berechnete Folgen) zu erzeugen, asynchrone Kontrollflüsse zu modellieren oder potenziell unendliche Datenströme zu erzeugen, ohne den Speicher zu erschöpfen. Der Generator pausiert bei jedem yield-Ausdruck und setzt die Ausführung beim nächsten Aufruf von next() fort.
Über next(value) kann ein Wert in den Generator hineingegeben werden, der als Ergebnis des aktuellen yield-Ausdrucks erscheint. Mit return(value) kann der Generator vorzeitig abgeschlossen und mit throw(error) kann ein Fehler in ihn hineingereicht werden. Sobald der Generator beendet ist (entweder durch return oder weil die Funktion ihr Ende erreicht hat), liefert jeder weitere Aufruf von next() { value: undefined, done: true }.
Generator ist keine direkt aufrufbare Klasse — Instanzen entstehen ausschließlich durch Aufrufen einer function*-Deklaration. Die Klasse selbst ist über Object.getPrototypeOf(function*(){}).prototype erreichbar, aber nicht global zugänglich.
Rückgabewert
function*-Generatorfunktion erzeugt.Beispiele
Einfache Ganzzahl-Sequenz mit Generator
function* range(start, end, step = 1) {
for (let i = start; i < end; i += step) {
yield i;
}
}
const gen = range(0, 10, 2);
console.log(gen.next()); // { value: 0, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 4, done: false }
// Nutzung in for...of
for (const n of range(1, 5)) {
console.log(n);
}
// 1, 2, 3, 4
// Spread
const arr = [...range(0, 6, 2)];
console.log(arr); // [0, 2, 4]
Zwei-Wege-Kommunikation und vorzeitiger Abbruch
function* accumulator() {
let total = 0;
while (true) {
const value = yield total; // Wert hineingeben, aktuellen Stand herausgeben
if (value === null) break;
total += value;
}
return total;
}
const acc = accumulator();
console.log(acc.next()); // { value: 0, done: false } — Generator starten
console.log(acc.next(10)); // { value: 10, done: false }
console.log(acc.next(20)); // { value: 30, done: false }
console.log(acc.next(null)); // { value: 30, done: true } — Schleife bricht ab
// Fehler in den Generator werfen
function* safe() {
try {
yield 1;
yield 2;
} catch (e) {
console.error('Fehler abgefangen:', e.message);
yield -1;
}
}
const s = safe();
console.log(s.next()); // { value: 1, done: false }
console.log(s.throw(new Error('Oops!'))); // Fehler abgefangen: Oops! → { value: -1, done: false }
console.log(s.next()); // { value: undefined, done: true }
// Wichtig · Fallstricke
Einmalige Verwendung: Ein Generator-Objekt kann nur einmal vollständig durchlaufen werden. Wird das Ende erreicht, ist der Generator erschöpft. Um erneut zu iterieren, muss die Generatorfunktion erneut aufgerufen werden.
Kein Zurückspulen: Generatoren sind vorwärtsgerichtete Iteratoren. Es gibt keine Methode, um zu einem früheren yield-Punkt zurückzukehren.
return(value): Schließt den Generator vorzeitig ab. Der Generator wechselt in den Zustand done: true und finally-Blöcke in der Generatorfunktion werden noch ausgeführt.
Delegieren mit yield*: Mit yield* kann ein Generator die Kontrolle an ein anderes Iterable übergeben und dessen Werte transparent weitergeben.
Browserunterstützung: Generator und function* werden von allen modernen Browsern sowie Node.js ab Version 4 unterstützt (vollständig ab Node.js 6).