Start · Sprachen · JavaScript · Referenz · Generator.prototype.throw()

Generator.prototype.throw()

Methode

Wirft eine Ausnahme an der Stelle, an der der Generator gerade angehalten ist, und setzt ihn fort — so, als stünde dort eine <code>throw</code>-Anweisung.

seit JavaScript ES2015 Kategorie: method-property

Signatur

Generator.prototype.throw(exception)

Beschreibung

throw() setzt einen angehaltenen Generator fort. Statt eines Wertes wird dabei eine Ausnahme an der Position des aktuellen yield ausgelöst. Der Generator kann sie mit try...catch abfangen und weiterlaufen, er kann aufräumen (finally) oder die Ausnahme weitergeben.

Fängt der Generator die Ausnahme ab und erreicht danach ein weiteres yield, liefert throw() ein normales Ergebnisobjekt { value, done: false }. Endet er stattdessen mit return, bekommt man { value, done: true }. Fängt er die Ausnahme nicht ab, wird der Generator beendet und die Ausnahme erreicht den Aufrufer von throw().

Typische Einsatzfälle sind Koroutinen-Bibliotheken wie das frühere co oder Redux-Saga: Schlägt ein asynchroner Vorgang fehl, wird der Fehler per gen.throw(err) in den Generator zurückgegeben. Dort lässt er sich wie in einer async-Funktion mit try...catch behandeln. Außerdem nutzt man throw(), um einen Generator von außen gezielt abzubrechen und seine Aufräumlogik auszuführen.

Parameter

Name Typ Default Beschreibung
$exception Pflicht any Der Wert, der im Generator geworfen werden soll. Am besten eine Instanz von Error, damit ein Stacktrace vorhanden ist.

Rückgabewert

Typ
IteratorResult<T> ({ value: any, done: boolean })
Beschreibung
Ein Ergebnisobjekt, wenn der Generator die Ausnahme abfängt und danach ein yield oder return erreicht. Wird die Ausnahme nicht abgefangen, gibt es keinen Rückgabewert: Die Ausnahme wird an den Aufrufer weitergereicht.

Beispiele

Fehler im Generator abfangen und weiterlaufen

function* zaehler() {
  let n = 0;
  while (true) {
    try {
      yield n++;
    } catch (err) {
      console.log('Abgefangen:', err.message);
      n = 0; // Zurücksetzen nach Fehler
    }
  }
}

const gen = zaehler();
console.log(gen.next());
console.log(gen.next());
console.log(gen.throw(new Error('Reset')));
console.log(gen.next());
{ value: 0, done: false } { value: 1, done: false } Abgefangen: Reset { value: 0, done: false } { value: 1, done: false }

Nicht abgefangene Ausnahme beendet den Generator

function* einfach() {
  yield 1;
  yield 2;
}

const gen = einfach();
gen.next();

try {
  gen.throw(new Error('Abbruch'));
} catch (err) {
  console.log('Beim Aufrufer:', err.message);
}

console.log(gen.next()); // Generator ist beendet
Beim Aufrufer: Abbruch { value: undefined, done: true }

Mini-Koroutinen-Runner: Promise-Fehler in den Generator zurückgeben

const run = (genFn) => new Promise((resolve, reject) => {
  const gen = genFn();
  const step = (method, arg) => {
    let result;
    try {
      result = gen[method](arg);
    } catch (err) {
      return reject(err);
    }
    if (result.done) return resolve(result.value);
    Promise.resolve(result.value).then(
      (v) => step('next', v),
      (e) => step('throw', e) // Fehler als Ausnahme in den Generator
    );
  };
  step('next');
});

run(function* () {
  try {
    yield Promise.reject(new Error('Netzwerkfehler'));
  } catch (err) {
    console.log('Im Generator behandelt:', err.message);
    return 'Fallback-Daten';
  }
}).then(console.log);
Im Generator behandelt: Netzwerkfehler Fallback-Daten

Aufräumen mit finally beim Abbruch

function* ressource() {
  console.log('Verbindung geöffnet');
  try {
    yield 'Daten 1';
    yield 'Daten 2';
  } finally {
    console.log('Verbindung geschlossen');
  }
}

const gen = ressource();
gen.next();
try {
  gen.throw(new Error('Timeout'));
} catch (e) {
  console.log('Fehler:', e.message);
}
Verbindung geöffnet Verbindung geschlossen Fehler: Timeout

// Wichtig · Fallstricke

  • Frisch erzeugter Generator: Wurde next() noch nie aufgerufen, steht der Generator noch vor der ersten Anweisung. Ein try...catch im Körper kann die Ausnahme dann nicht abfangen. Sie wird sofort an den Aufrufer weitergereicht, und der Generator ist danach beendet.
  • Beendeter Generator: Auch nach done: true wirft throw() die übergebene Ausnahme direkt beim Aufrufer.
  • Läuft der Generator gerade (Aufruf von throw() aus dem eigenen Körper heraus), entsteht ein TypeError („Generator is already running“).
  • Wird ein finally-Block ausgeführt, der selbst yield enthält, pausiert der Generator dort. Die Ausnahme wird erst später weitergegeben.
  • Bei yield* reicht throw() die Ausnahme an den inneren Iterator weiter. Hat dieser keine throw-Methode, wird der innere Iterator geschlossen und ein TypeError ausgelöst.
  • Asynchrone Generatoren haben ein eigenes AsyncGenerator.prototype.throw(), das ein Promise zurückgibt.
  • Kompatibilität: in allen modernen Browsern und in Node.js ab 4 verfügbar.