Signatur
Beschreibung
Symbol.dispose ist eine statische, nicht beschreibbare und nicht konfigurierbare Dateneigenschaft von Symbol. Ihr Wert ist ein wohlbekanntes Symbol. Es gehört zum Vorschlag Explicit Resource Management. Ein Objekt gilt als disposable (freigebbar), wenn es unter diesem Schlüssel eine Methode besitzt, die die Ressource synchron wieder freigibt, etwa Dateihandles schließt, Listener entfernt oder Sperren löst.
Die Methode wird automatisch aufgerufen, wenn eine mit using deklarierte Variable ihren Gültigkeitsbereich verlässt. Das gilt sowohl beim normalen Blockende als auch bei return, break oder einer geworfenen Ausnahme. Mehrere using-Deklarationen werden in umgekehrter Reihenfolge freigegeben (LIFO). Das ersetzt fehleranfällige try…finally-Konstrukte.
Die Methode erhält keine Argumente, und ihr Rückgabewert wird ignoriert. Für asynchrones Aufräumen gibt es das Gegenstück Symbol.asyncDispose zusammen mit await using. Ein Objekt, das nur Symbol.dispose besitzt, lässt sich auch mit await using verwenden. Mit DisposableStack kann man mehrere Ressourcen gebündelt verwalten.
Beispiele
Eigene freigebbare Klasse mit using
class DbConnection {
constructor(name) {
this.name = name;
console.log(`Verbindung ${name} geöffnet`);
}
query(sql) {
console.log(`[${this.name}] ${sql}`);
}
[Symbol.dispose]() {
console.log(`Verbindung ${this.name} geschlossen`);
}
}
const loadUsers = () => {
using db = new DbConnection('main');
db.query('SELECT * FROM users');
return 'fertig';
}; // hier wird db[Symbol.dispose]() automatisch aufgerufen
console.log(loadUsers());
Event-Listener automatisch entfernen – auch bei Fehlern
const listen = (target, type, handler) => {
target.addEventListener(type, handler);
return {
[Symbol.dispose]() {
target.removeEventListener(type, handler);
console.log(`Listener für "${type}" entfernt`);
}
};
};
const target = new EventTarget();
try {
using sub = listen(target, 'ping', () => console.log('ping empfangen'));
target.dispatchEvent(new Event('ping'));
throw new Error('Abbruch');
} catch (err) {
console.log('Fehler:', err.message);
}
target.dispatchEvent(new Event('ping')); // keine Ausgabe mehr
Freigabe-Reihenfolge (LIFO) und Prüfung auf Unterstützung
if (typeof Symbol.dispose !== 'symbol') {
console.log('Explicit Resource Management wird nicht unterstützt');
} else {
const resource = (name) => ({
[Symbol.dispose]: () => console.log(`${name} freigegeben`)
});
{
using a = resource('A');
using b = resource('B');
console.log('Block läuft');
}
console.log(typeof Symbol.dispose, Symbol.dispose.description);
}
Manuell über DisposableStack bündeln
const stack = new DisposableStack();
const timer = setInterval(() => {}, 1000);
stack.defer(() => { clearInterval(timer); console.log('Timer gestoppt'); });
stack.use({ [Symbol.dispose]: () => console.log('Cache geleert') });
// DisposableStack ist selbst disposable:
stack[Symbol.dispose]();
console.log(stack.disposed);
// Wichtig · Fallstricke
- Kompatibilität: Das Feature ist noch neu. Es wird von Chrome/Edge ab 134, Firefox ab 134 und Node.js ab 24 unterstützt (in Node.js 18–22 gibt es nur
Symbol.dispose, aber keinusing). Safari unterstützt es derzeit nicht. TypeScript unterstützt es ab 5.2 (mitlib: "esnext.disposable"). Für ältere Umgebungen braucht man einen Polyfill wiecore-jsund fürusingeinen Transpiler wie Babel oder TypeScript. usingist nicht auf oberster Ebene eines klassischen Skripts erlaubt. Es funktioniert nur in Blöcken, Funktionen und Modulen.using-Variablen sind wieconstnicht neu zuweisbar.- Der Wert muss ein Objekt mit aufrufbarer
[Symbol.dispose]-Methode odernull/undefinedsein. Sonst wird bereits bei der Deklaration einTypeErrorgeworfen. - Wirft die Dispose-Methode selbst einen Fehler, während schon eine andere Ausnahme aktiv ist, werden beide zu einem
SuppressedErrorzusammengefasst (errorundsuppressed). - Die Methode sollte idempotent sein, also bei mehrfachem Aufruf keinen Schaden anrichten. Sie sollte außerdem synchron arbeiten. Ein zurückgegebenes Promise wird nicht abgewartet, dafür gibt es
Symbol.asyncDispose. - Einige Plattform-Objekte sind bereits disposable, z. B. Iterator-Helper (
Iterator.prototype[Symbol.dispose]ruftreturn()auf) und in Node.js u. a. Timer undFileHandle.