Start · Sprachen · JavaScript · Referenz · DisposableStack.prototype.use()

DisposableStack.prototype.use()

Methode

Registriert einen Wert mit <code>[Symbol.dispose]()</code>-Methode auf dem Stack, damit er beim Aufräumen des Stacks automatisch freigegeben wird, und gibt ihn unverändert zurück.

seit JavaScript Explicit Resource Management (ES2026); Chrome/Edge Kategorie: method-property

Signatur

DisposableStack.prototype.use(value)

Beschreibung

use() nimmt ein Objekt entgegen, das das Disposable-Protokoll implementiert – also eine Methode unter dem Schlüssel Symbol.dispose besitzt – und legt es auf dem DisposableStack ab. Wird der Stack später per dispose() oder über eine using-Deklaration freigegeben, ruft er für jeden registrierten Wert dessen [Symbol.dispose]()-Methode auf, und zwar in umgekehrter Reihenfolge der Registrierung (LIFO).

Die Methode ist das programmatische Gegenstück zu using x = …: Sie eignet sich, wenn die Zahl der Ressourcen erst zur Laufzeit feststeht (z. B. in Schleifen), wenn Ressourcen bedingt angelegt werden oder wenn mehrere Ressourcen gebündelt und per move() an einen Aufrufer weitergereicht werden sollen.

Da use() den übergebenen Wert unverändert zurückgibt, lässt sich Anlegen und Registrieren in einer Zeile erledigen: const datei = stack.use(openFile(pfad));. null und undefined werden akzeptiert und einfach ignoriert.

Für Werte, die nicht dem Protokoll folgen, gibt es adopt() (Wert + eigene Aufräumfunktion) und defer() (nur Aufräumfunktion).

Parameter

Name Typ Default Beschreibung
$value Pflicht Disposable | null | undefined Das zu registrierende Objekt. Muss eine aufrufbare Methode unter Symbol.dispose besitzen. null und undefined sind erlaubt und werden ignoriert.

Rückgabewert

Typ
Disposable | null | undefined
Beschreibung
Genau der übergebene value, unverändert – praktisch für die Verkettung mit der Erzeugung der Ressource.

Beispiele

Mehrere Ressourcen registrieren – Freigabe in LIFO-Reihenfolge

const createResource = (name) => ({
  name,
  [Symbol.dispose]() {
    console.log(`${name} freigegeben`);
  }
});

const stack = new DisposableStack();
const db = stack.use(createResource('Datenbank'));
const log = stack.use(createResource('Logdatei'));

console.log(`Arbeite mit ${db.name} und ${log.name}`);
stack.dispose();
console.log(stack.disposed);
Arbeite mit Datenbank und Logdatei Logdatei freigegeben Datenbank freigegeben true

Dynamische Anzahl von Ressourcen mit using

const openConnection = (host) => ({
  host,
  [Symbol.dispose]() {
    console.log(`Verbindung zu ${host} geschlossen`);
  }
});

const pingAll = (hosts) => {
  using stack = new DisposableStack();
  const connections = hosts.map((h) => stack.use(openConnection(h)));
  return connections.map((c) => `${c.host}: ok`);
}; // hier werden alle Verbindungen automatisch geschlossen

console.log(pingAll(['a.example', 'b.example']));
Verbindung zu b.example geschlossen Verbindung zu a.example geschlossen [ 'a.example: ok', 'b.example: ok' ]

Ressourcen sicher bündeln und per move() weitergeben

const makeRes = (name) => ({
  name,
  [Symbol.dispose]() { console.log(`${name} zu`); }
});

class Session {
  #stack;
  constructor(failOnCache = false) {
    using stack = new DisposableStack();
    this.socket = stack.use(makeRes('Socket'));
    if (failOnCache) throw new Error('Cache nicht verfügbar');
    this.cache = stack.use(makeRes('Cache'));
    // Erfolg: Besitz übernehmen, 'stack' räumt nichts mehr auf
    this.#stack = stack.move();
  }
  [Symbol.dispose]() { this.#stack.dispose(); }
}

try {
  new Session(true);
} catch (e) {
  console.log(e.message);
}

{
  using session = new Session();
  console.log('Session aktiv');
}
Socket zu Cache nicht verfügbar Session aktiv Cache zu Socket zu

null/undefined werden ignoriert, Fehler bei ungültigen Werten

const stack = new DisposableStack();

const optional = null;
console.log(stack.use(optional)); // kein Fehler

try {
  stack.use({ close() {} }); // kein Symbol.dispose
} catch (e) {
  console.log(e.constructor.name);
}

stack.dispose();
try {
  stack.use(null);
} catch (e) {
  console.log(e.constructor.name);
}
null TypeError ReferenceError

// Wichtig · Fallstricke

  • TypeError, wenn value weder null/undefined ist noch eine aufrufbare [Symbol.dispose]-Methode besitzt – das gilt auch für primitive Werte.
  • ReferenceError, wenn der Stack bereits freigegeben wurde (disposed === true) oder sein Inhalt per move() weitergegeben wurde.
  • Die Methode [Symbol.dispose] wird beim Aufruf von use() ausgelesen und gespeichert. Spätere Änderungen am Objekt wirken sich nicht mehr aus.
  • Objekte, die nur Symbol.asyncDispose implementieren, lehnt DisposableStack ab. Dafür gibt es AsyncDisposableStack.prototype.use().
  • Wirft eine Dispose-Methode beim Aufräumen einen Fehler, werden die übrigen Ressourcen trotzdem freigegeben. Mehrere Fehler werden zu einem SuppressedError zusammengefasst.
  • Kompatibilität: Die Methode gehört zum neuen Explicit-Resource-Management-Standard. Safari unterstützt ihn derzeit noch nicht, für ältere Umgebungen gibt es Polyfills (z. B. core-js). Die Syntax using braucht zusätzlich Unterstützung durch Engine oder Transpiler (TypeScript 5.2+, Babel).