Start · Sprachen · JavaScript · Referenz · Symbol.dispose

Symbol.dispose

Eigenschaft

Wohlbekanntes Symbol, unter dem ein Objekt seine synchrone Aufräummethode ablegt, die eine <code>using</code>-Deklaration am Blockende automatisch aufruft.

seit JavaScript ES2026 (Explicit Resource Management); Chrome 134+ Kategorie: method-property

Signatur

Symbol.dispose

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());
Verbindung main geöffnet [main] SELECT * FROM users Verbindung main geschlossen fertig

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
ping empfangen Listener für "ping" entfernt Fehler: Abbruch

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);
}
Block läuft B freigegeben A freigegeben symbol Symbol.dispose

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);
Cache geleert Timer gestoppt true

// 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 kein using). Safari unterstützt es derzeit nicht. TypeScript unterstützt es ab 5.2 (mit lib: "esnext.disposable"). Für ältere Umgebungen braucht man einen Polyfill wie core-js und für using einen Transpiler wie Babel oder TypeScript.
  • using ist nicht auf oberster Ebene eines klassischen Skripts erlaubt. Es funktioniert nur in Blöcken, Funktionen und Modulen. using-Variablen sind wie const nicht neu zuweisbar.
  • Der Wert muss ein Objekt mit aufrufbarer [Symbol.dispose]-Methode oder null/undefined sein. Sonst wird bereits bei der Deklaration ein TypeError geworfen.
  • Wirft die Dispose-Methode selbst einen Fehler, während schon eine andere Ausnahme aktiv ist, werden beide zu einem SuppressedError zusammengefasst (error und suppressed).
  • 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] ruft return() auf) und in Node.js u. a. Timer und FileHandle.