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

DisposableStack.prototype.adopt()

Methode

Legt einen Wert ohne <code>[Symbol.dispose]</code>-Methode auf den <code>DisposableStack</code> und registriert dafür eine eigene Aufräumfunktion.

seit JavaScript ECMAScript Explicit Resource Management (ES2026, S Kategorie: method-property

Signatur

DisposableStack.prototype.adopt(value, onDispose)

Beschreibung

adopt() ist die Brücke zwischen klassischen Ressourcen und dem neuen Mechanismus zur expliziten Ressourcenverwaltung (using, DisposableStack). Viele bestehende APIs liefern Werte, die kein Disposable-Protokoll implementieren: Dateideskriptoren aus fs.openSync(), Timer-IDs von setInterval(), Objekt-URLs von URL.createObjectURL() oder Datenbankverbindungen älterer Bibliotheken. Mit adopt() übergibst du so einen Wert zusammen mit einer Funktion, die weiß, wie er freigegeben wird.

Wird der Stack entsorgt – durch stack.dispose() oder automatisch am Ende eines Blocks mit using stack = new DisposableStack() –, wird onDispose(value) aufgerufen. Dabei gilt, wie bei allen Einträgen des Stacks, die LIFO-Reihenfolge: Was zuletzt registriert wurde, wird zuerst aufgeräumt. So werden abhängige Ressourcen in der richtigen Reihenfolge freigegeben.

Die Methode gibt value unverändert zurück. Deshalb kannst du Erzeugen und Registrieren in einer Zeile schreiben: const fd = stack.adopt(fs.openSync(pfad), fs.closeSync). Das ist der Unterschied zu defer(), das nur eine Callback-Funktion ohne zugehörigen Wert annimmt, und zu use(), das einen Wert erwartet, der bereits [Symbol.dispose] besitzt.

Parameter

Name Typ Default Beschreibung
$value Pflicht any Beliebiger Wert (auch null oder ein primitiver Wert wie eine Timer-ID), der beim Entsorgen des Stacks aufgeräumt werden soll.
$onDispose Pflicht (value: any) => void Aufräumfunktion. Sie wird beim Entsorgen mit value als einzigem Argument und this === undefined aufgerufen. Ihr Rückgabewert wird ignoriert.

Rückgabewert

Typ
any
Beschreibung
Den unveränderten value, damit Erzeugen und Registrieren in einem Ausdruck möglich sind.

Beispiele

Dateideskriptor in Node.js automatisch schließen

import fs from 'node:fs';

function ersteZeile(pfad) {
  using stack = new DisposableStack();
  // fs.openSync liefert nur eine Zahl – kein Disposable
  const fd = stack.adopt(fs.openSync(pfad, 'r'), (fd) => {
    fs.closeSync(fd);
    console.log(`Deskriptor ${fd} geschlossen`);
  });

  const puffer = Buffer.alloc(64);
  const gelesen = fs.readSync(fd, puffer, 0, 64, 0);
  return puffer.toString('utf8', 0, gelesen).split('\n')[0];
} // hier wird fs.closeSync(fd) automatisch aufgerufen

console.log(ersteZeile('./package.json'));
Deskriptor 23 geschlossen {

Timer und Objekt-URL im Browser aufräumen (LIFO-Reihenfolge)

const stack = new DisposableStack();

const intervalId = stack.adopt(
  setInterval(() => console.log('tick'), 1000),
  (id) => { clearInterval(id); console.log('Intervall gestoppt'); }
);

const blob = new Blob(['Hallo'], { type: 'text/plain' });
const url = stack.adopt(URL.createObjectURL(blob), (u) => {
  URL.revokeObjectURL(u);
  console.log('Objekt-URL freigegeben');
});

console.log(typeof intervalId, url.startsWith('blob:'));

// Später, z. B. beim Verlassen einer Ansicht:
stack.dispose();
console.log(stack.disposed);
number true Objekt-URL freigegeben Intervall gestoppt true

Ressourcen sammeln und per move() an den Aufrufer übergeben

function oeffneVerbindungen() {
  using stack = new DisposableStack();
  const a = stack.adopt({ name: 'db' }, (c) => console.log(`${c.name} geschlossen`));
  const b = stack.adopt({ name: 'cache' }, (c) => console.log(`${c.name} geschlossen`));
  // Wirft hier etwas, werden a und b sofort aufgeräumt.
  // Bei Erfolg übernimmt ein neuer Stack die Verantwortung:
  return { a, b, stack: stack.move() };
}

{
  const { a, b, stack } = oeffneVerbindungen();
  using _ = stack;
  console.log('Arbeite mit', a.name, 'und', b.name);
}
Arbeite mit db und cache cache geschlossen db geschlossen

// Wichtig · Fallstricke

  • TypeError, wenn onDispose keine Funktion ist. Das wird sofort beim Aufruf von adopt() geprüft, nicht erst beim Entsorgen.
  • ReferenceError, wenn der Stack bereits entsorgt ist (stack.disposed === true), auch nach move().
  • onDispose wird mit this === undefined aufgerufen. Methoden wie conn.close verlieren dabei ihren Kontext. Übergib stattdessen eine Pfeilfunktion ((c) => c.close()) oder eine mit bind gebundene Funktion.
  • Wirft eine Aufräumfunktion einen Fehler, werden die übrigen Einträge trotzdem entsorgt. Mehrere Fehler werden zu einem SuppressedError zusammengefasst.
  • Asynchrone Aufräumfunktionen, zum Beispiel await conn.end(), werden hier nicht abgewartet. Verwende dafür AsyncDisposableStack.prototype.adopt() zusammen mit await using.
  • Kompatibilität: Die Funktion ist neu und wird noch nicht überall unterstützt (Stand 2025 fehlt sie z. B. in Safari). Prüfe vor der Nutzung mit typeof DisposableStack !== 'undefined' oder verwende ein Polyfill (z. B. core-js). TypeScript unterstützt die Funktion ab Version 5.2 mit lib: ["esnext.disposable"].