Signatur
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
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'));
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);
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);
}
// Wichtig · Fallstricke
- TypeError, wenn
onDisposekeine Funktion ist. Das wird sofort beim Aufruf vonadopt()geprüft, nicht erst beim Entsorgen. - ReferenceError, wenn der Stack bereits entsorgt ist (
stack.disposed === true), auch nachmove(). onDisposewird mitthis === undefinedaufgerufen. Methoden wieconn.closeverlieren dabei ihren Kontext. Übergib stattdessen eine Pfeilfunktion ((c) => c.close()) oder eine mitbindgebundene Funktion.- Wirft eine Aufräumfunktion einen Fehler, werden die übrigen Einträge trotzdem entsorgt. Mehrere Fehler werden zu einem
SuppressedErrorzusammengefasst. - Asynchrone Aufräumfunktionen, zum Beispiel
await conn.end(), werden hier nicht abgewartet. Verwende dafürAsyncDisposableStack.prototype.adopt()zusammen mitawait 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 mitlib: ["esnext.disposable"].