Signatur
Beschreibung
dispose() gibt alle Ressourcen frei, die über use(), adopt() oder defer() bei einem DisposableStack registriert wurden. Die Disposer laufen in umgekehrter Reihenfolge (LIFO): Was zuletzt registriert wurde, wird zuerst entsorgt. So werden abhängige Ressourcen sauber abgebaut, zum Beispiel erst die Transaktion und danach die Datenbankverbindung.
Die Methode ist identisch mit DisposableStack.prototype[Symbol.dispose](). Deshalb entsorgt eine Deklaration wie using stack = new DisposableStack() den Stapel am Blockende automatisch. Ein manueller Aufruf von dispose() ist dann sinnvoll, wenn es kein using gibt, etwa in älterem Code, in try…finally-Konstrukten oder wenn Sie den Zeitpunkt der Freigabe selbst bestimmen wollen.
Nach dem Aufruf steht disposed auf true. Ein zweiter Aufruf von dispose() bewirkt nichts. Die Methoden use(), adopt(), defer() und move() werfen danach einen ReferenceError.
Wirft ein Disposer einen Fehler, werden die übrigen Disposer trotzdem aufgerufen. Am Ende wird der Fehler weitergeworfen. Bei mehreren Fehlern werden sie zu einem SuppressedError verschachtelt.
Rückgabewert
undefined). Kann aber einen Fehler werfen, wenn ein Disposer fehlschlägt.Beispiele
LIFO-Reihenfolge beim Aufräumen
const stack = new DisposableStack();
stack.defer(() => console.log('Verbindung geschlossen'));
stack.defer(() => console.log('Transaktion beendet'));
stack.defer(() => console.log('Cache geleert'));
stack.dispose();
console.log('disposed:', stack.disposed);
// Zweiter Aufruf bewirkt nichts
stack.dispose();
Manuelle Entsorgung mit try…finally (ohne using)
const openFile = (name) => ({
name,
[Symbol.dispose]() {
console.log(`${name} geschlossen`);
},
});
const processFiles = () => {
const stack = new DisposableStack();
try {
const a = stack.use(openFile('eingabe.csv'));
const b = stack.use(openFile('ausgabe.csv'));
console.log(`Verarbeite ${a.name} -> ${b.name}`);
} finally {
stack.dispose();
}
};
processFiles();
Fehlerbehandlung: SuppressedError bei mehreren Fehlern
const stack = new DisposableStack();
stack.defer(() => { throw new Error('Fehler A'); });
stack.defer(() => console.log('läuft trotzdem'));
stack.defer(() => { throw new Error('Fehler B'); });
try {
stack.dispose();
} catch (err) {
console.log(err instanceof SuppressedError);
console.log(err.error.message); // zuletzt geworfener Fehler
console.log(err.suppressed.message); // zuvor geworfener Fehler
}
Ressourcen nach Fehler im Konstruktor wieder freigeben
class Service {
#stack;
constructor(fail = false) {
const stack = new DisposableStack();
try {
stack.defer(() => console.log('Socket freigegeben'));
if (fail) throw new Error('Initialisierung fehlgeschlagen');
stack.defer(() => console.log('Timer gestoppt'));
this.#stack = stack.move(); // Besitz übernehmen
} finally {
stack.dispose(); // wirkt nur, wenn move() nicht erreicht wurde
}
}
dispose() {
this.#stack.dispose();
}
}
try { new Service(true); } catch (e) { console.log(e.message); }
const s = new Service();
s.dispose();
// Wichtig · Fallstricke
- Browser-Kompatibilität: Die Methode gehört zum Vorschlag „Explicit Resource Management“. Sie wird in Chrome/Edge ab 134, Firefox ab 134 und Node.js ab 24 unterstützt. Safari unterstützt sie noch nicht. Für ältere Umgebungen gibt es Polyfills, z. B.
core-js. - Nur synchron:
dispose()wartet nicht auf Promises. Gibt ein Disposer ein Promise zurück, wird es ignoriert. Für asynchrone Freigaben verwenden SieAsyncDisposableStackmitdisposeAsync(). - Fehler werden nicht verschluckt: Alle Disposer laufen, aber am Ende wird ein Fehler geworfen. Bei einem einzigen Fehler ist es genau dieser Fehler, bei mehreren ein verschachtelter
SuppressedError. Die Eigenschafterrorenthält den zuletzt geworfenen Fehler,suppresseddie vorherigen. - Nach der Entsorgung gesperrt:
use(),adopt(),defer()undmove()werfen dann einenReferenceError. Weitere Aufrufe vondispose()bewirken nichts und sind unschädlich. - Nach
move()gilt der ursprüngliche Stapel bereits als entsorgt. Ein anschließender Aufruf vondispose()ruft also keine Disposer mehr auf.