Start · Sprachen · JavaScript · Referenz · new FinalizationRegistry()

new FinalizationRegistry()

Methode

Erstellt ein <code>FinalizationRegistry</code>-Objekt, das eine Callback-Funktion aufruft, nachdem registrierte Objekte von der Garbage Collection freigegeben wurden.

seit JavaScript ES2021 Kategorie: method-property

Signatur

new FinalizationRegistry(callbackFn)

Beschreibung

Der Konstruktor FinalizationRegistry() erzeugt eine Registry. Mit register() meldet man dort Objekte an. Wird ein angemeldetes Objekt später von der Garbage Collection eingesammelt, ruft die Engine den übergebenen callbackFn auf. Dabei bekommt der Callback den Held Value, den man bei der Registrierung angegeben hat, und nicht das Objekt selbst, denn das existiert zu diesem Zeitpunkt nicht mehr.

Typische Einsatzfälle sind Aufräumarbeiten für externe Ressourcen, die an JavaScript-Objekte gekoppelt sind. Dazu gehören etwa Speicher in WebAssembly, native Handles, Einträge in Caches mit WeakRef-Werten oder Datei- und Socket-Handles in Node.js. Oft kombiniert man die Registry mit WeakRef, um Caches zu bauen, die sich selbst bereinigen.

Wichtig: Finalisierung ist nicht deterministisch. Die Spezifikation garantiert weder, wann der Callback läuft, noch ob er überhaupt läuft, etwa wenn das Programm vorher endet. Die Registry eignet sich deshalb nur als Sicherheitsnetz oder zur Optimierung, nie für Logik, die für das Programm wichtig ist.

Der Konstruktor muss mit new aufgerufen werden. Ein Aufruf ohne new wirft einen TypeError.

Parameter

Name Typ Default Beschreibung
$callbackFn Pflicht (heldValue: any) => void Funktion, die nach dem Einsammeln eines registrierten Objekts aufgerufen wird. Sie erhält als einziges Argument den heldValue, der bei register(target, heldValue) übergeben wurde. Ihr Rückgabewert wird ignoriert. Ist callbackFn keine Funktion, wird ein TypeError geworfen.

Rückgabewert

Typ
FinalizationRegistry
Beschreibung
Ein neues FinalizationRegistry-Objekt mit den Methoden register() und unregister().

Beispiele

Registry erstellen und Objekt registrieren

const registry = new FinalizationRegistry((heldValue) => {
  console.log(`Objekt eingesammelt: ${heldValue}`);
});

let user = { name: 'Anna' };
registry.register(user, 'user-Anna');

// Referenz entfernen – das Objekt kann jetzt eingesammelt werden
user = null;
// Irgendwann später (nicht garantiert):
Objekt eingesammelt: user-Anna

Selbstbereinigender Cache mit WeakRef

class WeakCache {
  #map = new Map();
  #registry = new FinalizationRegistry((key) => {
    // Nur löschen, wenn der Eintrag noch tot ist (kein neuer Wert unter dem Schlüssel)
    const ref = this.#map.get(key);
    if (ref && !ref.deref()) this.#map.delete(key);
  });

  set(key, value) {
    this.#map.set(key, new WeakRef(value));
    this.#registry.register(value, key);
  }

  get(key) {
    return this.#map.get(key)?.deref();
  }
}

const cache = new WeakCache();
const bild = { pixels: new Uint8Array(1024) };
cache.set('logo', bild);
console.log(cache.get('logo') === bild);
true

Explizites Freigeben mit Unregister-Token

const registry = new FinalizationRegistry((handle) => {
  console.warn(`Ressource ${handle} wurde nicht geschlossen – räume auf.`);
});

class FileHandle {
  constructor(id) {
    this.id = id;
    // this dient als Unregister-Token
    registry.register(this, id, this);
  }
  close() {
    console.log(`Schließe ${this.id}`);
    registry.unregister(this); // Sicherheitsnetz nicht mehr nötig
  }
}

const f = new FileHandle('datei-42');
f.close();
Schließe datei-42

// Wichtig · Fallstricke

  • Keine Garantie: Ob und wann der Callback läuft, hängt von der Engine, vom Speicherdruck und von der Laufzeit ab. Ressourcen sollte man immer ausdrücklich freigeben, etwa mit close() oder using. Die Registry dient nur als Absicherung.
  • Kein Verweis auf das Ziel: Der heldValue darf nicht das registrierte Objekt selbst sein, sonst wirft register() einen TypeError. Er sollte das Objekt auch nicht indirekt referenzieren, weil es sonst nie eingesammelt wird. Auch der Callback selbst darf das Ziel nicht über eine Closure festhalten.
  • Der Callback läuft asynchron in einem eigenen Job, nicht während der Garbage Collection. Ausnahmen im Callback werden als unbehandelte Fehler gemeldet.
  • Primitive Werte können nicht registriert werden. Nicht registrierte Symbole sind erst seit ES2023 erlaubt.
  • Kompatibilität: Chrome 84+, Firefox 79+, Safari 14.1+, Node.js 14.6+. In älteren Umgebungen ist keine Nachrüstung per Polyfill möglich.
  • Zum Testen lässt sich in Node.js mit node --expose-gc und global.gc() eine Garbage Collection erzwingen. Auch dann ist das Verhalten nicht garantiert.