Signatur
Beschreibung
Die Methode [Symbol.dispose]() setzt das Disposable-Protokoll für DisposableStack-Instanzen um. Deshalb kann ein Stack direkt mit using (oder await using) deklariert werden: Verlässt das Programm den Block, ruft die Laufzeit automatisch stack[Symbol.dispose]() auf. Das passiert auch dann, wenn im Block ein Fehler geworfen wird.
Es handelt sich um dasselbe Funktionsobjekt wie DisposableStack.prototype.dispose. Beim Aufruf werden alle Ressourcen, die mit use(), adopt() oder defer() registriert wurden, in umgekehrter Reihenfolge (LIFO) freigegeben. Danach gilt der Stack als entsorgt (disposed === true). Weitere Aufrufe bewirken nichts.
Wirft eine Freigabe-Funktion einen Fehler, werden die übrigen Ressourcen trotzdem freigegeben. Mehrere Fehler werden zu einem SuppressedError verkettet, der am Ende geworfen wird. In error steht der zuletzt aufgetretene Fehler, in suppressed der davor aufgetretene.
Einsatzgebiet: mehrere Ressourcen (Dateihandles, Sperren, Listener, Timer) gebündelt und ausnahmesicher aufräumen, ohne verschachtelte try…finally-Blöcke.
Rückgabewert
SuppressedError).Beispiele
Automatische Freigabe mit using
{
using stack = new DisposableStack();
stack.defer(() => console.log("Verbindung geschlossen"));
stack.defer(() => console.log("Datei geschlossen"));
console.log("Arbeite...");
} // hier ruft die Laufzeit stack[Symbol.dispose]() auf
Manueller Aufruf – mehrfach aufrufbar, nur einmal wirksam
console.log(DisposableStack.prototype[Symbol.dispose] === DisposableStack.prototype.dispose);
const stack = new DisposableStack();
stack.use({
[Symbol.dispose]() { console.log("Ressource freigegeben"); }
});
stack[Symbol.dispose]();
stack[Symbol.dispose](); // bewirkt nichts mehr
console.log(stack.disposed);
Fehler beim Freigeben werden zu SuppressedError verkettet
const stack = new DisposableStack();
stack.defer(() => { throw new Error("A"); });
stack.defer(() => { throw new Error("B"); });
try {
stack[Symbol.dispose]();
} catch (e) {
// B wird zuerst freigegeben, danach A
console.log(e instanceof SuppressedError, e.error.message, e.suppressed.message);
}
Ressourcen einer Klasse bündeln und im eigenen Dispose freigeben
class Widget {
#stack;
constructor(el) {
using stack = new DisposableStack();
const onClick = () => console.log("Klick");
el.addEventListener("click", onClick);
stack.defer(() => el.removeEventListener("click", onClick));
const id = setInterval(() => {}, 1000);
stack.defer(() => clearInterval(id));
// Erfolgreich aufgebaut: Ressourcen an die Instanz übertragen
this.#stack = stack.move();
}
[Symbol.dispose]() {
this.#stack[Symbol.dispose]();
}
}
{
using widget = new Widget(document.body);
// ... Widget benutzen
} // Listener und Intervall werden entfernt
// Wichtig · Fallstricke
- Kompatibilität: Explicit Resource Management ist neu (Chrome/Edge 134+, Firefox 134+, Node.js 24+). Safari unterstützt es noch nicht. Für ältere Umgebungen gibt es Polyfills (z. B. core-js) und Transpilierung mit TypeScript 5.2+ oder Babel.
usingist nur in Blöcken, Funktionen und auf oberster Ebene von Modulen erlaubt, nicht auf oberster Ebene klassischer Skripte.- Die Freigabe erfolgt synchron. Asynchrone Aufräumfunktionen werden nicht abgewartet – dafür
AsyncDisposableStackmitawait usingverwenden. - Nach der Freigabe werfen
use(),adopt(),defer()undmove()einenReferenceError. Mitdisposedlässt sich der Zustand prüfen. - Ein Fehler in einer Aufräumfunktion bricht die Freigabe der übrigen Ressourcen nicht ab. Wer Fehler auswertet, sollte die Kette über
SuppressedError.suppresseddurchlaufen. - Wird die Methode auf einem Objekt aufgerufen, das kein
DisposableStackist, wird einTypeErrorgeworfen.