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

AsyncDisposableStack.prototype.adopt()

Methode

Registriert einen beliebigen Wert ohne <code>[Symbol.asyncDispose]()</code> auf dem Stack und legt eine eigene, gegebenenfalls asynchrone Aufräumfunktion dafür fest.

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

Signatur

AsyncDisposableStack.prototype.adopt(value, onDispose)

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

Typ
any
Beschreibung
Genau den übergebenen 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();
Ergebnis von "SELECT * FROM users" db geschlossen

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);
Timer gestoppt räume Transaktion auf räume Verbindung auf true

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);
}
Session aktiv, Socket 42 Cache geleert Socket 42 zu

// Wichtig · Fallstricke

  • TypeError: Ist onDispose keine Funktion, wirft adopt() sofort einen TypeError. Der Wert wird dann nicht registriert.
  • ReferenceError: Wurde der Stack schon aufgeräumt (stack.disposed === true) oder mit move() geleert, wirft adopt() einen ReferenceError. 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 SuppressedError verkettet, den disposeAsync() am Ende auslöst.
  • Kein Bezug zu this: onDispose wird ohne this aufgerufen. Übergib daher nicht direkt conn.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 using braucht außerdem Unterstützung in der Syntax, sonst hilft ein Transpiler wie TypeScript 5.2+ oder Babel zusammen mit einem Polyfill wie core-js.