Es gibt Fälle, in denen man eine schwere Initialisierung nur beim ersten Zugriff ausführen und den generierten Wert danach wiederverwenden möchte. Dieses Pattern implementiert das einfach, ohne den Overhead eines Speicher-Caches.
Code
export interface Reusable<T> { value: T;}
export function reusable<T>(init: () => T): Reusable<T> { return { get value() { const value = init(); Object.defineProperty(this, "value", { value }); return value; }, };}Anwendungsbeispiele
Fester Zeitstempel
const timestamp = reusable(() => new Date());
// Date wird beim ersten Zugriff generiertconsole.log(timestamp.value); // 2025-01-18T09:00:00.000Z
// Bei nachfolgenden Zugriffen wird derselbe Wert zurückgegebenconsole.log(timestamp.value); // 2025-01-18T09:00:00.000ZSchweres Konfigurationsladen
const config = reusable(() => { // Datei laden, Umgebungsvariablen parsen, etc. return loadConfigFromFile();});
// Konfiguration wird nur bei Bedarf geladenfunction processData() { const settings = config.value; // Laden wird nur beim ersten Zugriff ausgeführt // ...}Funktionsweise der Implementierung
- Führt die init-Funktion beim ersten Getter-Zugriff aus
- Überschreibt value als Dateneigenschaft mit Object.defineProperty
- Bei nachfolgenden Zugriffen wird der Getter nicht aufgerufen und der Wert direkt zurückgegeben
Dadurch entstehen Initialisierungskosten nur beim ersten Zugriff, danach ist die Leistung vergleichbar mit dem Zugriff auf eine normale Eigenschaft.
Vergleich mit Speicher-Cache
Unterschiede zu Speicher-Caches (wie Map):
- Dieses Pattern ist auf einzelne Werte spezialisiert
- Keine Schlüsselverwaltung wie bei Map erforderlich
- Garbage Collection verhält sich wie bei normalen Objekten
Umgekehrt sollten Sie Map oder WeakMap verwenden, wenn Sie mehrere Werte cachen möchten.
Einschränkungen
Einmal initialisiert ändert sich der Wert nie. Um neu zu initialisieren, müssen Sie eine neue reusable-Instanz erstellen. Wenn die init-Funktion eine Exception wirft, wird dieselbe Exception bei nachfolgenden Zugriffen erneut geworfen.
hsb.horse