Start · Sprachen · JavaScript · Referenz · AsyncGenerator.prototype.next()

AsyncGenerator.prototype.next()

Methode

Setzt einen asynchronen Generator fort und gibt ein <code>Promise</code> zurück, das mit dem nächsten Ergebnis <code>{ value, done }</code> erfüllt wird.

seit JavaScript ES2018 Kategorie: method-property

Signatur

AsyncGenerator.prototype.next(value)

Beschreibung

Mit next() fordert man bei einem asynchronen Generator (definiert über async function*) den nächsten Wert an. Anders als beim synchronen Generator liefert die Methode nicht direkt ein Ergebnisobjekt, sondern ein Promise. Es wird mit einem Objekt der Form { value, done } erfüllt, sobald der Generator das nächste yield erreicht oder endet.

Das optionale Argument value wird im Generator zum Ergebnis des yield-Ausdrucks, an dem er zuvor angehalten hat. So kann der aufrufende Code Daten in den Generator zurückgeben, etwa für Steuerbefehle oder Rückmeldungen. Der Wert des ersten next()-Aufrufs wird verworfen, weil zu diesem Zeitpunkt noch kein yield erreicht wurde.

Meistens ruft man next() nicht selbst auf, sondern nutzt for await...of, das die Methode intern aufruft. Der direkte Aufruf ist sinnvoll, wenn man Werte gezielt einzeln abruft (z. B. „nächste Seite laden“), Werte in den Generator einspeist oder eigene Kombinatoren für Datenströme schreibt.

Aufrufe von next() werden intern in eine Warteschlange gestellt. Ruft man die Methode mehrmals auf, ohne auf das vorherige Promise zu warten, werden die Anfragen trotzdem der Reihe nach abgearbeitet. Die Ergebnisse kommen also nie in falscher Reihenfolge an.

Parameter

Name Typ Default Beschreibung
$value any undefined Wert, der im Generator als Ergebnis des aktuell pausierten yield-Ausdrucks ankommt. Beim ersten Aufruf wird er ignoriert.

Rückgabewert

Typ
Promise<IteratorResult<T>>
Beschreibung
Ein Promise, das mit { value, done } erfüllt wird. Solange der Generator Werte liefert, ist done gleich false. Nach dem Ende ist done gleich true, und value enthält den return-Wert (sonst undefined). Wirft der Generator einen Fehler, wird das Promise mit diesem Fehler abgelehnt.

Beispiele

Werte einzeln abrufen

const wait = (ms) => new Promise((r) => setTimeout(r, ms));

async function* countdown(from) {
  for (let i = from; i > 0; i--) {
    await wait(100);
    yield i;
  }
  return 'Start!';
}

const gen = countdown(3);
console.log(await gen.next());
console.log(await gen.next());
console.log(await gen.next());
console.log(await gen.next());
console.log(await gen.next());
{ value: 3, done: false } { value: 2, done: false } { value: 1, done: false } { value: 'Start!', done: true } { value: undefined, done: true }

Paginierte API bei Bedarf nachladen

async function* fetchPages(baseUrl) {
  let page = 1;
  while (true) {
    const res = await fetch(`${baseUrl}?page=${page}`);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    const items = await res.json();
    if (items.length === 0) return;
    yield items;
    page++;
  }
}

const pages = fetchPages('https://api.example.com/posts');

document.querySelector('#mehr').addEventListener('click', async () => {
  try {
    const { value, done } = await pages.next();
    if (done) {
      console.log('Keine weiteren Einträge.');
      return;
    }
    console.log(`${value.length} Einträge geladen`);
  } catch (err) {
    console.error('Laden fehlgeschlagen:', err.message);
  }
});
20 Einträge geladen

Werte per next(value) in den Generator senden

async function* akkumulator() {
  let summe = 0;
  while (true) {
    const zahl = yield summe; // empfängt den Wert aus next()
    summe += await Promise.resolve(zahl ?? 0);
  }
}

const acc = akkumulator();
await acc.next();            // bis zum ersten yield laufen; Argument würde ignoriert
console.log((await acc.next(5)).value);
console.log((await acc.next(10)).value);
console.log((await acc.next(2)).value);
5 15 17

Parallele Aufrufe werden in der richtigen Reihenfolge abgearbeitet

async function* langsam() {
  yield 'a';
  await new Promise((r) => setTimeout(r, 200));
  yield 'b';
  yield 'c';
}

const g = langsam();
// Drei Anfragen gleichzeitig: Der Generator arbeitet sie nacheinander ab
const ergebnisse = await Promise.all([g.next(), g.next(), g.next(), g.next()]);
console.log(ergebnisse.map((r) => r.value));
[ 'a', 'b', 'c', undefined ]

// Wichtig · Fallstricke

  • Immer mit await auswerten: gen.next().done ist undefined, weil next() ein Promise zurückgibt und kein Ergebnisobjekt. Richtig ist (await gen.next()).done.
  • Erster Wert wird verworfen: Das Argument des ersten next()-Aufrufs kommt im Generator nie an. Werte für den Start übergibt man besser als Parameter der Generatorfunktion.
  • Fehler: Wirft der Generator einen Fehler, wird das Promise abgelehnt und der Generator gilt danach als beendet. Weitere Aufrufe liefern { value: undefined, done: true }. Unbehandelte Ablehnungen führen zu unhandledrejection-Warnungen, deshalb try...catch verwenden.
  • Aufräumen: Wer next() manuell aufruft und vorzeitig aufhört, sollte return() aufrufen, damit finally-Blöcke im Generator laufen (z. B. zum Schließen von Verbindungen). for await...of erledigt das bei break automatisch.
  • yield mit Promise: In asynchronen Generatoren wird ein mit yield übergebenes Promise automatisch aufgelöst. value ist also nie selbst ein Promise.
  • Kompatibilität: Seit ES2018 in allen modernen Browsern und in Node.js ab Version 10 verfügbar. await auf oberster Ebene (wie in den Beispielen) funktioniert nur in ES-Modulen.