Signatur
Beschreibung
Die Methode [Symbol.asyncDispose]() auf AsyncIterator.prototype sorgt dafür, dass jeder eingebaute asynchrone Iterator – etwa Instanzen von Async-Generatoren oder der Iterator eines ReadableStream – als asynchron entsorgbare Ressource gilt. Damit kannst du ihn direkt mit einer await using-Deklaration binden. Sobald der umgebende Block verlassen wird, egal ob normal, per return oder durch eine Ausnahme, ruft die Laufzeit automatisch await iterator[Symbol.asyncDispose]() auf.
Intern ist die Methode sehr schlank: Sie sucht die Methode return auf this. Gibt es sie, wird this.return() aufgerufen und abgewartet. Gibt es sie nicht, wird das Promise sofort mit undefined erfüllt. Bei Async-Generatoren heißt das: Laufende finally-Blöcke im Generator werden ausgeführt, und der Generator ist danach beendet.
Nützlich ist das vor allem, wenn du einen Iterator manuell mit next() abarbeitest und nicht bis zum Ende liest, zum Beispiel wenn du nur den ersten Datensatz aus einem Datenbank-Cursor, einem Netzwerk-Stream oder einer Seitenabfrage brauchst. Ohne await using müsstest du return() selbst in einem try…finally aufrufen. Bei for await…of ist die Methode dagegen nicht nötig, denn die Schleife ruft return() bei break oder einem Fehler schon selbst auf.
Rückgabewert
undefined erfüllt wird, sobald this.return() (falls vorhanden) fertig ist. Das Ergebnisobjekt von return() wird nicht weitergegeben. Wirft return() einen Fehler oder wird sein Promise abgelehnt, wird auch das zurückgegebene Promise abgelehnt.Beispiele
Async-Generator mit await using automatisch schließen
async function* datensaetze() {
console.log("Verbindung geöffnet");
try {
yield { id: 1 };
yield { id: 2 };
yield { id: 3 };
} finally {
// Läuft beim Entsorgen durch return()
console.log("Verbindung geschlossen");
}
}
const ersterDatensatz = async () => {
await using cursor = datensaetze();
const { value } = await cursor.next();
console.log("Gelesen:", value.id);
return value;
// Hier ruft die Laufzeit await cursor[Symbol.asyncDispose]() auf
};
await ersterDatensatz();
console.log("Fertig");
Methode direkt aufrufen und Wirkung prüfen
async function* zaehler() {
let i = 0;
while (true) yield i++;
}
const it = zaehler();
console.log(await it.next());
const ergebnis = await it[Symbol.asyncDispose]();
console.log(ergebnis); // Rückgabewert ist immer undefined
console.log(await it.next()); // Generator ist beendet
Eigenen asynchronen Iterator entsorgbar machen (mit Feature-Erkennung)
// AsyncIterator ist (noch) kein globales Objekt – Prototyp über einen Async-Generator ermitteln
const AsyncIteratorPrototype = Object.getPrototypeOf(
Object.getPrototypeOf((async function* () {}).prototype)
);
const quelle = Object.setPrototypeOf({
i: 0,
async next() {
return { value: this.i++, done: false };
},
async return() {
console.log("Quelle aufgeräumt");
return { value: undefined, done: true };
}
}, AsyncIteratorPrototype);
const lesen = async () => {
if (typeof quelle[Symbol.asyncDispose] !== "function") {
console.log("Explicit Resource Management wird nicht unterstützt");
return;
}
await using q = quelle; // erbt [Symbol.asyncDispose] vom Prototyp
console.log("Wert:", (await q.next()).value);
};
await lesen();