Signatur
Beschreibung
Die Methode [Symbol.asyncDispose]() implementiert das asynchrone Entsorgungsprotokoll für AsyncDisposableStack-Instanzen. Deshalb lässt sich ein Stack direkt mit await using deklarieren: Verlässt der Programmfluss den umgebenden Block (normal, durch return oder durch eine Ausnahme), ruft die Laufzeit automatisch stack[Symbol.asyncDispose]() auf und wartet auf das zurückgegebene Promise.
Diese Methode ist dasselbe Funktionsobjekt wie AsyncDisposableStack.prototype.disposeAsync(). Sie arbeitet alle über use(), adopt() und defer() registrierten Aufräumaktionen in umgekehrter Registrierungsreihenfolge (LIFO) ab und wartet jede einzelne ab, bevor die nächste startet. So werden abhängige Ressourcen in der richtigen Reihenfolge geschlossen, z. B. erst eine Transaktion, dann die Datenbankverbindung.
Werfen eine oder mehrere Aufräumaktionen einen Fehler, laufen die übrigen trotzdem weiter. Am Ende wird das Promise mit dem Fehler abgelehnt. Bei mehreren Fehlern werden sie in SuppressedError-Objekten verschachtelt. Nach dem Aufruf ist stack.disposed gleich true. Weitere Aufrufe bewirken nichts und liefern ein erfülltes Promise.
Direkt aufrufen muss man die Methode nur selten. Meist nutzt man await using oder, für bessere Lesbarkeit, den Alias disposeAsync(). Nützlich ist der direkte Zugriff zum Beispiel, wenn eine eigene Klasse ihren internen Stack in ihrer eigenen [Symbol.asyncDispose]()-Methode weiterreicht.
Rückgabewert
undefined erfüllt wird, sobald alle Aufräumaktionen abgeschlossen sind. Es wird abgelehnt, wenn mindestens eine Aufräumaktion einen Fehler geworfen hat; mehrere Fehler werden als SuppressedError verschachtelt.Beispiele
Automatische Entsorgung mit await using (LIFO-Reihenfolge)
// Als ES-Modul ausführen (Top-Level-await)
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
async function verarbeiteAuftrag() {
await using stack = new AsyncDisposableStack();
stack.defer(async () => {
await sleep(10);
console.log("Datenbankverbindung geschlossen");
});
stack.defer(async () => {
await sleep(10);
console.log("Temporäre Datei gelöscht");
});
console.log("Auftrag verarbeitet");
// Beim Verlassen des Blocks: await stack[Symbol.asyncDispose]()
}
await verarbeiteAuftrag();
Direkter Aufruf, Alias disposeAsync und wiederholte Aufrufe
console.log(
AsyncDisposableStack.prototype[Symbol.asyncDispose] ===
AsyncDisposableStack.prototype.disposeAsync
);
const stack = new AsyncDisposableStack();
stack.defer(() => console.log("aufgeräumt"));
await stack[Symbol.asyncDispose]();
console.log(stack.disposed);
// Zweiter Aufruf: bewirkt nichts, keine erneute Ausgabe
await stack[Symbol.asyncDispose]();
Fehlerbehandlung: mehrere Fehler als SuppressedError
const stack = new AsyncDisposableStack();
stack.defer(async () => { throw new Error("A"); });
stack.defer(async () => { throw new Error("B"); });
try {
await stack[Symbol.asyncDispose]();
} catch (e) {
// B läuft zuerst (LIFO), danach A; A ist der zuletzt aufgetretene Fehler
console.log(e instanceof SuppressedError, e.error.message, e.suppressed.message);
}
Eigene Klasse leitet die Entsorgung an ihren internen Stack weiter
class Sitzung {
#stack = new AsyncDisposableStack();
constructor(name) {
this.name = name;
this.#stack.defer(async () => console.log(`${name}: Verbindung getrennt`));
this.#stack.defer(async () => console.log(`${name}: Cache geleert`));
}
async [Symbol.asyncDispose]() {
await this.#stack[Symbol.asyncDispose]();
}
}
{
await using sitzung = new Sitzung("S1");
console.log(`${sitzung.name} aktiv`);
}