Start · Sprachen · JavaScript · Referenz · Generator

Generator

Klasse

Ein <code>Generator</code>-Objekt wird von einer Generatorfunktion zurückgegeben und implementiert sowohl das Iterator- als auch das Iterable-Protokoll.

seit JavaScript ES2015 Kategorie: core

Signatur

class Generator

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

Typ
Generator
Beschreibung
Instanzen werden implizit durch den Aufruf einer 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]
{ value: 0, done: false } { value: 2, done: false } { value: 4, done: false } 1 2 3 4 [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 }
{ value: 0, done: false } { value: 10, done: false } { value: 30, done: false } { value: 30, done: true } { value: 1, done: false } Fehler abgefangen: Oops! { value: -1, done: false } { 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).