TGViewer
Настоящий JavaScript Настоящий JavaScript @true_js · 5.89K subscribers
Post #3608 307
⁣WeakRef и FinalizationRegistry: слабые ссылки как production-ready инструмент управления памятью

В асинхронных пайплайнах — от Node.js-сервисов до SSR и heavy client-side кэширования — каждый временный объект (кэши, буферы, промисы, слушатели) держится сильной ссылкой, блокируя сборщик мусора. Типичная ошибка: держать в Map результаты дорогих API-вызовов, не понимая, что Map хранит сильные ссылки, и память растёт бесконтрольно.

WeakRef: слабая ссылка для кэширования без утечек
WeakRef позволяет GC очищать объект, если на него нет сильных ссылок. Идеально для кэша, где данные можно пересоздать — экономит память под нагрузкой:
const cache = new Map<string, WeakRef<any>>();
const registry = new FinalizationRegistry((key: string) => {
cache.delete(key);
});

async function fetchData(key: string): Promise<any> {
let ref = cache.get(key);
let cached = ref?.deref();
if (cached) return cached;

const data = await expensiveAPICall(key);
const weakRef = new WeakRef(data);
cache.set(key, weakRef);
registry.register(data, key);
return data;
}

GC решает, когда удалить объект. Если памяти хватает — данные живут. Если нет — кэш "сдувается" без ручной очистки и утечек.

FinalizationRegistry: детекция утечек и чистка ресурсов
Колбэк при удалении объекта — можно отслеживать, что объект не был освобождён вовремя:
class LeakDetector {
private registry: FinalizationRegistry<string>;
private active = new Map<string, number>();

constructor(onLeak: (name: string) => void) {
this.registry = new FinalizationRegistry((name: string) => {
const count = (this.active.get(name) ?? 0) - 1;
if (count <= 0) this.active.delete(name);
else this.active.set(name, count);
onLeak(name);
});
}

track(obj: object, name: string) {
this.active.set(name, (this.active.get(name) ?? 0) + 1);
this.registry.register(obj, name);
}
}

Практический совет: используй в отладке для обнаружения утечек долгоживущих объектов — подписок, web-сокетов, буферов.

Типобезопасная обёртка с generic
TypeScript дружит с WeakRef через generic, что даёт надёжные типы:
class WeakCache<T extends object> {
private refs = new Map<string, WeakRef<T>>();
private registry = new FinalizationRegistry<string>((key) => {
this.refs.delete(key);
});

set(key: string, value: T): void {
const ref = new WeakRef(value);
this.refs.set(key, ref);
this.registry.register(value, key);
}

get(key: string): T | undefined {
return this.refs.get(key)?.deref();
}
}

Предупреждение: WeakRef не работают с примитивами (string, number) — только объекты. Для примитивов используй WeakMap или обёртки. Также не используй WeakRef для критичных по времени кэшей — GC непредсказуем.

Вывод: Слабые ссылки — не экзотика, а инженерный инструмент для надёжного управления памятью, где главное правило — "используй, если данные можно пересоздать, и никогда не полагайся на детерминизм GC".
More from @true_js
  1. Oct 3, 2026Post #3963
  2. Oct 2, 2026😅 Айтишник отправил в одну компанию три одинаковых резюме и только одно дошло до финала О…
  3. Oct 2, 2026Post #3961
  4. Oct 2, 2026🤣 Правильно расставленные приоритеты в моей жизни би лайк: 💥 xCode Journal
  5. Oct 1, 2026🤯 Люди взбунтовались против «пыточной для ИИ» На GitHub заметили открытый проект AI Tortu…
  6. Oct 1, 2026День в Заонежье начинается ещё в дороге. Мы встретим вас в аэропорту или на вокзале. Дальш…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →