Signatur
Beschreibung
Die Methode move() erzeugt eine neue AsyncDisposableStack-Instanz und übergibt ihr alle Ressourcen und Entsorger, die bisher auf dem aktuellen Stack lagen. Die Reihenfolge bleibt erhalten. Danach gilt der ursprüngliche Stack als entsorgt (disposed === true). Die Entsorger werden dabei nicht aufgerufen, denn die Verantwortung für das Aufräumen geht vollständig auf den neuen Stack über.
Gebraucht wird das vor allem bei Ressourcen, die schrittweise aufgebaut werden: Man sammelt mehrere asynchrone Ressourcen in einem Stack, der mit await using deklariert ist. Scheitert ein Zwischenschritt, räumt der Stack am Blockende automatisch auf. Klappt alles, ruft man am Ende stack.move() auf. So wird beim Verlassen des Blocks nichts entsorgt, und die Ressourcen können an den Aufrufer weitergegeben werden, zum Beispiel als Feld eines Objekts, das selbst [Symbol.asyncDispose]() umsetzt.
Wurde der Stack schon entsorgt (durch disposeAsync() oder einen früheren move()-Aufruf), wirft move() einen ReferenceError.
Rückgabewert
AsyncDisposableStack, der alle Entsorger des ursprünglichen Stacks in derselben Reihenfolge enthält.Beispiele
Grundprinzip: Entsorger übertragen
const stack = new AsyncDisposableStack();
stack.defer(async () => console.log('Aufräumen A'));
stack.defer(async () => console.log('Aufräumen B'));
const moved = stack.move();
console.log(stack.disposed); // alter Stack
console.log(moved.disposed); // neuer Stack
await stack.disposeAsync(); // hat keine Wirkung mehr
await moved.disposeAsync(); // führt die Entsorger aus (LIFO)
Ressourcen sicher aufbauen und an den Aufrufer übergeben
const openResource = async (name) => {
console.log(`öffne ${name}`);
return {
name,
async [Symbol.asyncDispose]() { console.log(`schließe ${name}`); }
};
};
class Session {
#stack;
constructor(db, cache, stack) {
this.db = db;
this.cache = cache;
this.#stack = stack;
}
static async create() {
await using stack = new AsyncDisposableStack();
const db = stack.use(await openResource('db'));
const cache = stack.use(await openResource('cache'));
// Alles hat geklappt: Eigentum an die Session übergeben
return new Session(db, cache, stack.move());
}
async [Symbol.asyncDispose]() {
await this.#stack.disposeAsync();
}
}
{
await using session = await Session.create();
console.log('arbeite mit', session.db.name, session.cache.name);
}
Fehler beim Aufbau: automatisches Aufräumen
const createPair = async () => {
await using stack = new AsyncDisposableStack();
stack.defer(async () => console.log('Verbindung 1 geschlossen'));
throw new Error('Verbindung 2 fehlgeschlagen');
// wird nicht erreicht, move() findet also nicht statt
return stack.move();
};
try {
await createPair();
} catch (err) {
console.log('Fehler:', err.message);
}
ReferenceError bei bereits entsorgtem Stack
const stack = new AsyncDisposableStack();
await stack.disposeAsync();
try {
stack.move();
} catch (err) {
console.log(err.name);
}
// Wichtig · Fallstricke
- Kein Aufräumen:
move()ruft keinen Entsorger auf. Wer den zurückgegebenen Stack verwirft, ohne ihn zu entsorgen, hinterlässt offene Ressourcen. - ReferenceError: Ist der Stack bereits entsorgt, wirft
move()einen Fehler. Das gilt auch für einen zweitenmove()-Aufruf. - Nur einmal übertragen: Der alte Stack ist danach dauerhaft unbrauchbar. Aufrufe von
use(),adopt()oderdefer()auf ihm werfen ebenfalls einenReferenceError.disposeAsync()dagegen läuft stillschweigend ohne Wirkung durch. - Unterklassen: Der Rückgabewert ist immer ein einfacher
AsyncDisposableStack, keine Instanz einer eigenen Unterklasse. - Kompatibilität: Das gehört zum noch recht neuen Proposal Explicit Resource Management. Unterstützt wird es in Chromium ab 134, in Firefox ab 141 und in Node.js ab 24. Safari unterstützt es noch nicht. Für ältere Umgebungen braucht man ein Polyfill (z. B.
core-js) und fürawait usinggegebenenfalls einen Transpiler (TypeScript 5.2+, Babel).