Start · Sprachen · JavaScript · Referenz · AsyncDisposableStack.prototype.disposeAsync()

AsyncDisposableStack.prototype.disposeAsync()

Methode

Entsorgt den Stack: Alle registrierten Disposer werden in umgekehrter Reihenfolge aufgerufen und nacheinander abgewartet. Rückgabewert ist ein <code>Promise</code>.

seit JavaScript ES2026 (Explicit Resource Management); Chrome 134+ Kategorie: method-property

Signatur

AsyncDisposableStack.prototype.disposeAsync()

Beschreibung

disposeAsync() räumt einen AsyncDisposableStack auf. Alle Ressourcen und Aufräum-Callbacks, die du vorher mit use(), adopt() oder defer() registriert hast, werden in umgekehrter Reihenfolge (LIFO) aufgerufen. Die Methode wartet jeden Disposer mit await ab, bevor sie den nächsten startet. Das Aufräumen läuft also streng nacheinander und nicht parallel.

Du brauchst die Methode, wenn du mehrere asynchrone Ressourcen wie Datenbankverbindungen, Dateihandles oder Streams gemeinsam verwaltest und sie gezielt zu einem bestimmten Zeitpunkt freigeben willst. Meist rufst du sie aber gar nicht direkt auf: Mit await using stack = new AsyncDisposableStack() übernimmt die Laufzeit den Aufruf automatisch am Ende des Blocks. disposeAsync() ist dieselbe Funktion wie AsyncDisposableStack.prototype[Symbol.asyncDispose].

Nach dem Aufruf gilt der Stack als entsorgt (stack.disposed === true). Ein zweiter Aufruf von disposeAsync() tut nichts und erfüllt sich sofort mit undefined. Andere Methoden wie use(), defer() oder move() werfen danach dagegen einen ReferenceError.

Wirft ein Disposer einen Fehler, werden die übrigen Disposer trotzdem noch aufgerufen. Am Ende wird das Promise mit dem Fehler zurückgewiesen. Treten mehrere Fehler auf, werden sie in SuppressedError-Objekte verschachtelt: error enthält den zuletzt aufgetretenen Fehler, suppressed den vorherigen.

Rückgabewert

Typ
Promise<undefined>
Beschreibung
Ein Promise, das sich mit undefined erfüllt, sobald alle Disposer fertig sind. Hat mindestens ein Disposer einen Fehler geworfen, wird das Promise zurückgewiesen, bei mehreren Fehlern mit einem SuppressedError.

Beispiele

Reihenfolge des Aufräumens (LIFO)

const stack = new AsyncDisposableStack();

const warte = (ms) => new Promise((r) => setTimeout(r, ms));

stack.defer(async () => { await warte(50); console.log('1. registriert: Logger schließen'); });
stack.defer(async () => { await warte(10); console.log('2. registriert: DB trennen'); });
stack.defer(() => console.log('3. registriert: Cache leeren'));

await stack.disposeAsync();
console.log('disposed:', stack.disposed);

// Zweiter Aufruf tut nichts
await stack.disposeAsync();
3. registriert: Cache leeren 2. registriert: DB trennen 1. registriert: Logger schließen disposed: true

Mehrere Ressourcen verwalten und gezielt freigeben

const oeffneVerbindung = async (name) => {
  console.log(`${name} geöffnet`);
  return {
    name,
    query: async (sql) => `${name}: ${sql} -> ok`,
    close: async () => console.log(`${name} geschlossen`),
  };
};

const stack = new AsyncDisposableStack();
try {
  // adopt(): Wert + eigene Aufräumfunktion registrieren
  const primaer = stack.adopt(await oeffneVerbindung('primary'), (c) => c.close());
  const replika = stack.adopt(await oeffneVerbindung('replica'), (c) => c.close());
  console.log(await primaer.query('SELECT 1'));
  console.log(await replika.query('SELECT 2'));
} finally {
  await stack.disposeAsync();
}
primary geöffnet replica geöffnet primary: SELECT 1 -> ok replica: SELECT 2 -> ok replica geschlossen primary geschlossen

Fehlerbehandlung mit SuppressedError

const stack = new AsyncDisposableStack();
stack.defer(async () => { throw new Error('Datei konnte nicht geschlossen werden'); });
stack.defer(async () => { throw new Error('Socket-Timeout'); });
stack.defer(() => console.log('Läuft trotzdem'));

try {
  await stack.disposeAsync();
} catch (e) {
  console.log(e instanceof SuppressedError);
  console.log('error:', e.error.message);
  console.log('suppressed:', e.suppressed.message);
}
Läuft trotzdem true error: Datei konnte nicht geschlossen werden suppressed: Socket-Timeout

Automatisch mit await using

async function verarbeite() {
  await using stack = new AsyncDisposableStack();
  stack.defer(async () => console.log('Aufgeräumt'));
  console.log('Arbeite …');
  // Am Blockende ruft die Laufzeit stack[Symbol.asyncDispose]() auf,
  // das ist identisch mit disposeAsync()
}

await verarbeite();
Arbeite … Aufgeräumt

// Wichtig · Fallstricke

  • Kompatibilität: Die Methode gehört zum Vorschlag „Explicit Resource Management“ und ist noch neu. Unterstützt wird sie ab Chrome/Edge 134, Firefox 141, Node.js 24 und Deno. Safari unterstützt sie noch nicht. Für ältere Umgebungen gibt es Polyfills, z. B. core-js. Die Syntax await using braucht allerdings nativen Support oder einen Transpiler wie TypeScript 5.2+ oder Babel.
  • Immer mit await aufrufen. Ohne await läuft das Aufräumen im Hintergrund weiter. Fehler landen dann als unbehandelte Promise-Zurückweisung (unhandled rejection) in der Konsole.
  • Nacheinander, nicht parallel: Die Disposer laufen streng hintereinander. Viele langsame Disposer summieren ihre Laufzeiten. Wenn du parallel aufräumen willst, registriere einen einzelnen defer()-Callback mit Promise.all().
  • Nach dem Entsorgen werfen use(), adopt(), defer() und move() einen ReferenceError. Nur disposeAsync() selbst darf mehrfach aufgerufen werden.
  • Hast du die Ressourcen vorher mit move() auf einen neuen Stack übertragen, entsorgt disposeAsync() auf dem alten Stack nichts mehr.
  • Auch synchrone Disposables (Symbol.dispose) und synchrone defer()-Callbacks sind erlaubt. Ihr Ergebnis wird trotzdem mit await abgewartet.