Signatur
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
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);
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']));
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');
}
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);
}
// Wichtig · Fallstricke
- TypeError, wenn
valuewedernull/undefinedist 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 permove()weitergegeben wurde. - Die Methode
[Symbol.dispose]wird beim Aufruf vonuse()ausgelesen und gespeichert. Spätere Änderungen am Objekt wirken sich nicht mehr aus. - Objekte, die nur
Symbol.asyncDisposeimplementieren, lehntDisposableStackab. Dafür gibt esAsyncDisposableStack.prototype.use(). - Wirft eine Dispose-Methode beim Aufräumen einen Fehler, werden die übrigen Ressourcen trotzdem freigegeben. Mehrere Fehler werden zu einem
SuppressedErrorzusammengefasst. - 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
usingbraucht zusätzlich Unterstützung durch Engine oder Transpiler (TypeScript 5.2+, Babel).