Start · Sprachen · JavaScript · Referenz · DisposableStack.prototype.defer()

DisposableStack.prototype.defer()

Methode

Registriert eine Aufräumfunktion auf dem <code>DisposableStack</code>, die beim Entsorgen des Stacks aufgerufen wird. Registrierte Funktionen laufen in umgekehrter Reihenfolge (LIFO).

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

Signatur

DisposableStack.prototype.defer(onDispose)

Beschreibung

defer() legt eine beliebige Rückruffunktion auf einen DisposableStack. Beim Entsorgen des Stacks wird sie ohne Argumente aufgerufen. Das geschieht entweder explizit über stack.dispose() oder automatisch, sobald ein mit using deklarierter Block verlassen wird. So verhält sich defer() ähnlich wie defer in Go oder ein finally-Block, nur dass sich die Aufräumlogik direkt neben der Stelle registrieren lässt, an der die Ressource angelegt wird.

Die Methode eignet sich besonders für Ressourcen, die kein [Symbol.dispose]() implementieren, zum Beispiel Event-Listener, Timer, temporäre DOM-Änderungen oder Handles aus älteren APIs. Für Objekte, die bereits entsorgbar sind, verwendest du use(). Für einen Wert mit einer eigenen Aufräumfunktion ist adopt() gedacht.

Alle Rückrufe auf dem Stack werden in umgekehrter Registrierungsreihenfolge (LIFO) ausgeführt. Was zuletzt angelegt wurde, wird also zuerst freigegeben. Auf diese Weise bleiben Abhängigkeiten zwischen Ressourcen beim Aufräumen korrekt erhalten.

Parameter

Name Typ Default Beschreibung
$onDispose Pflicht () => void Funktion, die beim Entsorgen des Stacks ohne Argumente und mit this gleich undefined aufgerufen wird. Ihr Rückgabewert wird ignoriert.

Rückgabewert

Typ
undefined
Beschreibung
Die Methode gibt nichts zurück. Anders als use() und adopt() liefert sie keinen Wert, den man weiterverwenden könnte.

Beispiele

Aufräumen mit using und LIFO-Reihenfolge

function verarbeite() {
  using stack = new DisposableStack();

  console.log('Verbindung öffnen');
  stack.defer(() => console.log('Verbindung schließen'));

  console.log('Transaktion starten');
  stack.defer(() => console.log('Transaktion beenden'));

  console.log('Arbeite ...');
} // hier wird stack automatisch entsorgt

verarbeite();
Verbindung öffnen Transaktion starten Arbeite ... Transaktion beenden Verbindung schließen

Event-Listener und Timer zuverlässig entfernen

const beobachteFenster = () => {
  const stack = new DisposableStack();

  const onResize = () => console.log('Größe:', window.innerWidth);
  window.addEventListener('resize', onResize);
  stack.defer(() => window.removeEventListener('resize', onResize));

  const id = setInterval(() => console.log('Tick'), 1000);
  stack.defer(() => clearInterval(id));

  // Aufrufer erhält die Verantwortung fürs Aufräumen
  return stack;
};

const aufraeumen = beobachteFenster();
setTimeout(() => {
  aufraeumen.dispose();
  console.log('Alles entfernt:', aufraeumen.disposed);
}, 3500);
Tick Tick Tick Alles entfernt: true

Aufräumen nur im Fehlerfall mit move()

class Dienst {
  #stack;
  constructor() {
    using stack = new DisposableStack();
    const cache = new Map();
    stack.defer(() => { cache.clear(); console.log('Cache geleert'); });

    if (Math.random() < 0) throw new Error('Init fehlgeschlagen');

    // Erfolg: Ressourcen an die Instanz übergeben, lokal nicht entsorgen
    this.#stack = stack.move();
  }
  [Symbol.dispose]() {
    this.#stack.dispose();
  }
}

{
  using dienst = new Dienst();
  console.log('Dienst läuft');
}
Dienst läuft Cache geleert

// Wichtig · Fallstricke

  • Bereits entsorgter Stack: Ein Aufruf von defer() nach dispose() oder move() wirft einen ReferenceError.
  • Kein Callable: Ist onDispose keine Funktion, wird sofort ein TypeError geworfen, also schon beim Registrieren und nicht erst beim Entsorgen.
  • Fehler in Rückrufen: Wirft ein Rückruf, laufen die übrigen trotzdem weiter. Treten mehrere Fehler auf, werden sie in einem SuppressedError verkettet.
  • Asynchrones Aufräumen: Der Rückgabewert wird ignoriert, ein zurückgegebenes Promise wird also nicht abgewartet. Für asynchrones Aufräumen verwendest du AsyncDisposableStack.prototype.defer() zusammen mit await using.
  • Keine Argumente: Anders als bei adopt() erhält der Rückruf keinen Wert. Benötigte Daten musst du per Closure einschließen.
  • Kompatibilität: Die Methode gehört zu den noch recht neuen Funktionen für explizites Ressourcenmanagement (Chrome/Edge 134+, Firefox 134+, Node.js 24+). Safari unterstützt sie noch nicht vollständig. Bei Bedarf helfen Polyfills wie core-js oder Transpiler wie TypeScript 5.2+ bzw. Babel.