Signatur
Beschreibung
adopt() verbindet einen Wert mit einer Aufräumfunktion und legt beides auf einem AsyncDisposableStack ab. Das ist vor allem bei Ressourcen aus älteren Bibliotheken nützlich, etwa Datenbankverbindungen, Sockets oder Timern. Solche Objekte haben meist eine eigene Methode wie close() oder end(), implementieren aber weder [Symbol.asyncDispose]() noch [Symbol.dispose]().
Die Methode gibt value unverändert zurück. Deshalb lassen sich Erzeugen und Registrieren in einer Zeile schreiben: const conn = stack.adopt(await connect(), (c) => c.close());. Wenn der Stack aufgeräumt wird, ruft er onDispose(value) auf und wartet auf das Ergebnis mit await. Das passiert entweder über await stack.disposeAsync() oder automatisch am Blockende bei await using. Die Funktion darf also ein Promise zurückgeben.
Alle Einträge werden in umgekehrter Reihenfolge ihrer Registrierung aufgeräumt (LIFO). Wurde eine Ressource zuletzt geöffnet, wird sie also zuerst geschlossen. Das passt zu typischen Abhängigkeiten, zum Beispiel wenn eine Transaktion vor ihrer Verbindung beendet werden muss. Für Objekte, die das Disposable-Protokoll schon selbst umsetzen, nimmt man use(). Für reine Aufräum-Callbacks ohne zugehörigen Wert nimmt man defer().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $value Pflicht | any | Beliebiger Wert, z. B. ein Verbindungs- oder Handle-Objekt. Auch null und undefined sind erlaubt. |
|
| $onDispose Pflicht | (value: any) => void | Promise<void> | Aufräumfunktion. Sie wird beim Aufräumen mit value als einzigem Argument und this gleich undefined aufgerufen. Ein zurückgegebenes Promise wird abgewartet. |
Rückgabewert
value. Das erlaubt die direkte Zuweisung an eine Variable.Beispiele
Datenbankverbindung ohne Dispose-Protokoll sicher schließen
// Simulierte Legacy-Bibliothek mit close() statt Symbol.asyncDispose
const connect = async (name) => ({
name,
query: async (sql) => `Ergebnis von "${sql}"`,
close: async function () {
await new Promise((r) => setTimeout(r, 10));
console.log(`${this.name} geschlossen`);
},
});
const loadUsers = async () => {
await using stack = new AsyncDisposableStack();
const db = stack.adopt(await connect('db'), (c) => c.close());
const result = await db.query('SELECT * FROM users');
console.log(result);
return result;
}; // hier wird db.close() automatisch abgewartet
await loadUsers();
LIFO-Reihenfolge beim Aufräumen
const stack = new AsyncDisposableStack();
stack.adopt('Verbindung', async (v) => console.log(`räume ${v} auf`));
stack.adopt('Transaktion', async (v) => console.log(`räume ${v} auf`));
const timer = stack.adopt(setInterval(() => {}, 1000), (id) => {
clearInterval(id);
console.log('Timer gestoppt');
});
await stack.disposeAsync();
console.log(stack.disposed);
Ressourcen in einer Fabrikfunktion bündeln und mit move() übergeben
const openSession = async () => {
await using stack = new AsyncDisposableStack();
const socket = stack.adopt({ id: 42 }, async (s) => console.log(`Socket ${s.id} zu`));
const cache = stack.adopt(new Map(), (m) => { m.clear(); console.log('Cache geleert'); });
// Schlägt hier etwas fehl, räumt der Stack alles auf.
// Bei Erfolg geht die Verantwortung an den Aufrufer über:
const owned = stack.move();
return {
socket,
cache,
[Symbol.asyncDispose]: () => owned.disposeAsync(),
};
};
{
await using session = await openSession();
console.log('Session aktiv, Socket', session.socket.id);
}
// Wichtig · Fallstricke
- TypeError: Ist
onDisposekeine Funktion, wirftadopt()sofort einenTypeError. Der Wert wird dann nicht registriert. - ReferenceError: Wurde der Stack schon aufgeräumt (
stack.disposed === true) oder mitmove()geleert, wirftadopt()einenReferenceError. Die Ressource wird in diesem Fall nicht aufgeräumt, darum muss sich der Aufrufer selbst kümmern. - Fehler beim Aufräumen: Werfen mehrere Aufräumfunktionen einen Fehler, laufen trotzdem alle übrigen. Die Fehler werden zu einem
SuppressedErrorverkettet, dendisposeAsync()am Ende auslöst. - Kein Bezug zu
this:onDisposewird ohnethisaufgerufen. Übergib daher nicht direktconn.close, sondern(c) => c.close(). Sonst verliert die Methode ihren Kontext. - Kompatibilität: Gehört zum Vorschlag „Explicit Resource Management“ (ES2026). Unterstützt in Chrome/Edge 134+, Firefox 134+, Node.js 24+ und Deno. In Safari noch nicht verfügbar.
await usingbraucht außerdem Unterstützung in der Syntax, sonst hilft ein Transpiler wie TypeScript 5.2+ oder Babel zusammen mit einem Polyfill wiecore-js.