Signatur
Beschreibung
Symbol.asyncDispose ist ein wohlbekanntes Symbol aus dem Vorschlag Explicit Resource Management. Ein Objekt, das unter diesem Symbol eine Methode hat, gilt als asynchron entsorgbar (Protokoll AsyncDisposable). Die Methode gibt normalerweise ein Promise zurück und räumt die Ressource auf, z. B. durch Schließen einer Datenbankverbindung, eines Datei-Handles oder eines Netzwerk-Streams.
Richtig nützlich wird das Symbol zusammen mit der Deklaration await using: Verlässt der Programmfluss den umgebenden Block, egal ob regulär, über return oder durch eine geworfene Ausnahme, ruft die Laufzeit obj[Symbol.asyncDispose]() auf und wartet auf das Ergebnis. Mehrere Ressourcen werden in umgekehrter Deklarationsreihenfolge freigegeben. Damit fallen die sonst nötigen und fehleranfälligen try/finally-Konstrukte weg.
Hat ein Objekt keine Methode [Symbol.asyncDispose], greift await using ersatzweise auf [Symbol.dispose] zurück. Für mehrere oder dynamisch hinzukommende Ressourcen gibt es AsyncDisposableStack. Die Eigenschaft selbst ist nicht beschreibbar, nicht aufzählbar und nicht konfigurierbar.
Beispiele
Eigene asynchron entsorgbare Ressource mit await using
class DbConnection {
constructor(name) {
this.name = name;
console.log(`${name}: verbunden`);
}
async query(sql) {
return `Ergebnis von "${sql}"`;
}
async [Symbol.asyncDispose]() {
// z. B. Verbindung sauber schließen
await new Promise((r) => setTimeout(r, 50));
console.log(`${this.name}: getrennt`);
}
}
const main = async () => {
await using db = new DbConnection('db1');
console.log(await db.query('SELECT 1'));
// Am Blockende wird db[Symbol.asyncDispose]() aufgerufen und abgewartet
};
await main();
console.log('fertig');
Aufräumen auch bei Fehlern, in umgekehrter Reihenfolge
const resource = (name) => ({
async [Symbol.asyncDispose]() {
console.log(`${name} freigegeben`);
},
});
const run = async () => {
await using a = resource('A');
await using b = resource('B');
throw new Error('Abbruch');
};
try {
await run();
} catch (err) {
console.log('Gefangen:', err.message);
}
Manuelle Nutzung ohne await using (Fallback)
const handle = {
open: true,
async [Symbol.asyncDispose]() {
this.open = false;
},
};
try {
console.log('Arbeite, offen:', handle.open);
} finally {
// Protokoll direkt aufrufen, wenn die Syntax nicht verfügbar ist
await handle[Symbol.asyncDispose]?.();
}
console.log('offen:', handle.open);
console.log(Symbol.asyncDispose.description);
Mehrere Ressourcen mit AsyncDisposableStack bündeln
const openTemp = (id) => ({
id,
async [Symbol.asyncDispose]() {
console.log(`Temp ${id} gelöscht`);
},
});
const process = async () => {
await using stack = new AsyncDisposableStack();
const files = [1, 2, 3].map((id) => stack.use(openTemp(id)));
stack.defer(async () => console.log('Log-Eintrag geschrieben'));
console.log(`${files.length} Dateien verarbeitet`);
};
await process();
// Wichtig · Fallstricke
- Kompatibilität:
Symbol.asyncDisposeundawait usingsind recht neu (Chromium 134+, Firefox 141+, Node.js 24+). In Safari fehlen sie noch. Node.js stellt das Symbol schon seit 18.18/20.4 bereit, die Syntax kam aber erst später. TypeScript unterstützt beides ab 5.2 (lib: \"esnext.disposable\"). Für ältere Umgebungen ist ein Polyfill nötig, z. B.core-js. Die Syntax selbst muss transpiliert werden. await usinggeht nur dort, wo auchawaiterlaubt ist, also inasync-Funktionen oder auf der obersten Ebene eines Moduls. Ein Einsatz auf oberster Ebene einesswitch-caseohne Block ist nicht erlaubt.- Wirft die Aufräummethode einen Fehler, während schon ein anderer Fehler aktiv ist, fasst die Laufzeit beide in einem
SuppressedErrorzusammen (errorundsuppressed). - Die Werte
nullundundefinedsind beiawait usingerlaubt und werden übersprungen. Andere Werte ohne[Symbol.asyncDispose]oder[Symbol.dispose]lösen einenTypeErroraus. - Die Aufräummethode sollte idempotent sein, also einen zweiten Aufruf ohne Fehler überstehen. Sie sollte nicht zu lange blockieren, denn das Verlassen des Blocks wartet auf sie.