Signatur
Beschreibung
AsyncDisposableStack ist Teil des Explicit Resource Management-Vorschlags (ECMAScript 2025) und ermöglicht die geordnete, asynchrone Freigabe von Ressourcen wie Datenbankverbindungen, Dateisystem-Handles oder Netzwerk-Sockets. Der Stapel funktioniert nach dem LIFO-Prinzip (Last In, First Out): Ressourcen werden in umgekehrter Reihenfolge ihrer Registrierung freigegeben.
Ressourcen können mit use(), adopt() oder defer() auf dem Stapel registriert werden. Beim Aufruf von disposeAsync() – oder beim Verlassen eines await using-Blocks – werden alle registrierten Disposer der Reihe nach asynchron aufgerufen. Fehler werden gesammelt und als SuppressedError gemeldet, sodass kein Disposer übersprungen wird.
AsyncDisposableStack implementiert das Symbol.asyncDispose-Protokoll und kann daher direkt mit der await using-Syntax in Verbindung mit dem expliziten Ressourcen-Management genutzt werden. Im Gegensatz zu DisposableStack unterstützt er asynchrone Disposer-Funktionen (d. h. Funktionen, die ein Promise zurückgeben).
- Verwende
use()für Objekte, die bereitsSymbol.asyncDisposeimplementieren. - Verwende
adopt()für Ressourcen, die kein Dispose-Protokoll kennen (z. B. rohe Handles). - Verwende
defer()für beliebige asynchrone Aufräum-Callbacks ohne zugehörige Ressource.
Rückgabewert
AsyncDisposableStack-Instanz mit einem leeren Stapel.Beispiele
Grundlegende Verwendung mit await using
// Simulierter Datenbankverbindungs-Typ mit asyncDispose
const createDbConnection = async () => {
const conn = {
query: async (sql) => ({ rows: [{ id: 1 }] }),
[Symbol.asyncDispose]: async () => {
console.log("Datenbankverbindung wird geschlossen...");
// await conn.close();
}
};
return conn;
};
async function main() {
await using stack = new AsyncDisposableStack();
// Datenbankverbindung registrieren
const db = stack.use(await createDbConnection());
const result = await db.query("SELECT * FROM users");
console.log("Ergebnis:", result.rows);
// Am Ende des Blocks / bei Verlassen des Scopes wird stack.disposeAsync() automatisch aufgerufen
}
await main();
// Ausgabe:
// Ergebnis: [{ id: 1 }]
// Datenbankverbindung wird geschlossen...
adopt() und defer() für externe Ressourcen
// Simulierter File-Handle ohne Symbol.asyncDispose
const openFile = async (path) => {
console.log(`Datei geöffnet: ${path}`);
return { path, fd: 42 };
};
const closeFile = async (handle) => {
console.log(`Datei geschlossen: ${handle.path} (fd=${handle.fd})`);
};
async function processFiles() {
await using stack = new AsyncDisposableStack();
// adopt(): Ressource + eigene Cleanup-Funktion
const fileA = stack.adopt(await openFile("a.txt"), closeFile);
const fileB = stack.adopt(await openFile("b.txt"), closeFile);
// defer(): Beliebiger asynchroner Aufräum-Callback
stack.defer(async () => {
console.log("Temporäre Dateien werden gelöscht...");
});
console.log(`Verarbeite: ${fileA.path} und ${fileB.path}`);
// Beim Verlassen: defer zuerst (LIFO), dann b.txt, dann a.txt
}
await processFiles();
Manuelles disposeAsync() und move()
async function example() {
const stack = new AsyncDisposableStack();
stack.defer(async () => console.log("Cleanup A"));
stack.defer(async () => console.log("Cleanup B"));
console.log("Disposed:", stack.disposed); // false
// Eigentümerschaft an einen anderen Stack übertragen
const outerStack = stack.move();
console.log("Alter Stack disposed:", stack.disposed); // true (übertragen)
// Manuell aufräumen
await outerStack.disposeAsync();
console.log("Outer Stack disposed:", outerStack.disposed); // true
}
await example();
// Wichtig · Fallstricke
Browser-Kompatibilität: AsyncDisposableStack ist Teil von ECMAScript 2025 und zum Zeitpunkt dieser Dokumentation noch nicht in allen Browsern standardmäßig verfügbar. Node.js unterstützt es ab Version 22+ hinter einem Flag bzw. ab Node.js 23+ nativ. Prüfe die aktuelle Browser-Kompatibilität auf caniuse.com oder MDN.
Fehlerbehandlung: Wenn mehrere Disposer Fehler werfen, werden diese als SuppressedError verschachtelt – der neueste Fehler ist in error, der ältere in suppressed. Alle Disposer werden immer ausgeführt, auch wenn vorherige fehlschlagen.
Einmaliger Aufruf: Nach dem Aufruf von disposeAsync() ist der Stack als disposed markiert; weitere Aufrufe von disposeAsync() sind ein No-op. Versuche, nach dem Dispose neue Ressourcen zu registrieren, werfen einen ReferenceError.
Synchrone Alternative: Für rein synchrone Ressourcen steht DisposableStack mit using (ohne await) zur Verfügung.