Start · Sprachen · JavaScript · Referenz · new AsyncDisposableStack()

new AsyncDisposableStack()

Methode

Der Konstruktor <code>AsyncDisposableStack()</code> erzeugt einen leeren Stapel, der asynchron freizugebende Ressourcen sammelt und sie später in umgekehrter Reihenfolge aufräumt.

seit JavaScript Explicit Resource Management (TC39 Stage 3, geplan Kategorie: method-property

Signatur

new AsyncDisposableStack()

Beschreibung

Mit new AsyncDisposableStack() erzeugst du einen zunächst leeren Container für Aufräumarbeiten. Über use(), adopt() und defer() registrierst du Ressourcen oder Aufräum-Callbacks. Rufst du disposeAsync() auf, werden alle Einträge in umgekehrter Reihenfolge (LIFO) abgearbeitet. Jeder Aufruf wird mit await abgewartet, bevor der nächste startet.

Am häufigsten kombinierst du den Stapel mit der Deklaration await using: await using stack = new AsyncDisposableStack();. Verlässt das Programm den Block, auch durch eine Ausnahme, räumt der Stapel automatisch auf, weil er selbst [Symbol.asyncDispose]() implementiert.

Das lohnt sich, wenn du mehrere Ressourcen nacheinander öffnest, zum Beispiel Datenbankverbindung, Dateihandle und Lock, oder wenn Objekte kein Symbol.asyncDispose haben. Mit move() kannst du die Verantwortung für die gesammelten Ressourcen an einen neuen Stapel übergeben. So baust du etwa einen Konstruktor, der nur bei Erfolg die Ressourcen behält und sie bei einem Fehler sofort freigibt.

Rückgabewert

Typ
AsyncDisposableStack
Beschreibung
Ein neues, leeres AsyncDisposableStack-Objekt. Seine Eigenschaft disposed steht zu Beginn auf false.

Beispiele

Stapel erzeugen und Aufräumarbeiten registrieren

const stack = new AsyncDisposableStack();

stack.defer(async () => {
  console.log('Verbindung geschlossen');
});
stack.defer(async () => {
  console.log('Cache geleert');
});

console.log(stack.disposed);
await stack.disposeAsync();
console.log(stack.disposed);
false Cache geleert Verbindung geschlossen true

Automatisches Aufräumen mit await using

const openConnection = async (name) => ({
  name,
  async [Symbol.asyncDispose]() {
    console.log(`${name} geschlossen`);
  }
});

const run = async () => {
  await using stack = new AsyncDisposableStack();
  const db = stack.use(await openConnection('DB'));
  const cache = stack.use(await openConnection('Cache'));
  console.log(`Arbeite mit ${db.name} und ${cache.name}`);
}; // Hier wird automatisch aufgeräumt

await run();
Arbeite mit DB und Cache Cache geschlossen DB geschlossen

Ressourcen ohne Symbol.asyncDispose per adopt() einbinden

import { open } from 'node:fs/promises';

const readFirstLine = async (path) => {
  await using stack = new AsyncDisposableStack();
  const handle = stack.adopt(await open(path), (h) => h.close());
  const { buffer, bytesRead } = await handle.read(Buffer.alloc(256), 0, 256, 0);
  return buffer.toString('utf8', 0, bytesRead).split('\n')[0];
};

console.log(await readFirstLine('./package.json'));
{

Verantwortung mit move() übertragen

const createService = async () => {
  await using stack = new AsyncDisposableStack();
  stack.defer(async () => console.log('Ressource A freigegeben'));
  stack.defer(async () => console.log('Ressource B freigegeben'));
  // Hätte es bis hier einen Fehler gegeben, wäre sofort aufgeräumt worden.
  const owned = stack.move();
  return {
    async [Symbol.asyncDispose]() { await owned.disposeAsync(); }
  };
};

const service = await createService();
console.log('Service läuft');
await service[Symbol.asyncDispose]();
Service läuft Ressource B freigegeben Ressource A freigegeben

// Wichtig · Fallstricke

  • Nur mit new aufrufbar: AsyncDisposableStack() ohne new wirft einen TypeError. Der Konstruktor nimmt keine Argumente entgegen.
  • Kompatibilität: Die Methode gehört zum Vorschlag „Explicit Resource Management“. Unterstützt wird sie ab Chrome/Edge 134, Firefox 141 und Node.js 24, Safari fehlt noch. Für ältere Umgebungen gibt es Polyfills (z. B. core-js), und await using lässt sich mit TypeScript 5.2+ oder Babel transpilieren.
  • Nach dem Aufräumen gesperrt: Ist der Stapel einmal aufgeräumt (disposed === true), werfen use(), adopt(), defer() und move() einen ReferenceError. Ein erneuter Aufruf von disposeAsync() bewirkt dagegen nichts.
  • Fehler beim Aufräumen: Werfen mehrere Callbacks, laufen trotzdem alle restlichen weiter. Am Ende werden die Fehler zu einem SuppressedError verschachtelt.
  • Nacheinander, nicht parallel: Die Callbacks werden der Reihe nach abgewartet. Sehr viele langsame Freigaben summieren sich daher zeitlich.
  • Für rein synchrone Ressourcen nimmst du DisposableStack mit using. Das ist schlanker, weil keine Promises nötig sind.