JS Advanced

WeakRef и FinalizationRegistry

Понять, как WeakRef создаёт слабые ссылки на объекты и как FinalizationRegistry уведомляет об удалении. Почему GC timing недетерминирован.

Продвинутый (Advanced)
Нужно знать:WeakMap и WeakSetОбъекты

Кратко

WeakRef — объект-ссылка на другой объект. .deref() возвращает объект или undefined (если GC уже удалил). FinalizationRegistry — callback при удалении объекта. GC timing недетерминирован — нельзя полагаться на порядок удаления.


Подробно

WeakRef: let target = { heavy: 'data' }; const ref = new WeakRef(target);

console.log(ref.deref()); // { heavy: 'data' }

target = null; // объект может быть собран GC

// Позже (GC неопределённо когда) console.log(ref.deref()); // undefined (или объект, если GC не сработал)

FinalizationRegistry: const registry = new FinalizationRegistry((heldValue) => { console.log(Объект ${heldValue} удалён); });

let obj = { data: 'важные данные' }; registry.register(obj, 'myObject');

obj = null; // GC может удалить → callback вызовется

Ограничения:

  • .deref() может вернуть undefined в любой момент
  • GC timing НЕ детерминирован
  • Нельзя полагаться на порядок удаления
  • WeakRef + FinalizationRegistry = niche API

Где НЕ использовать:

  • Как основной механизм управления памятью
  • В критических системах
  • Где нужна предсказуемость

Ментальная модель

WeakRef — как адрес пропавшего человека. Вы знаете адрес (ref), но не уверены, жив ли ещё человек (объект). .deref() — проверка: «Ещё здесь?» (undefined — нет). FinalizationRegistry — уведомление от соседей: «Он уехал».


Примеры

**Самый простой:**

javascript
let obj = { value: 42 };
const ref = new WeakRef(obj);

console.log(ref.deref()); // { value: 42 }

obj = null;
// GC может удалить объект
// ref.deref() вернёт undefined

Простейший WeakRef: ссылка на объект.

**Простой:**

javascript
// FinalizationRegistry
const registry = new FinalizationRegistry((id) => {
  console.log(`Cache entry ${id} cleaned up`);
});

function createCachedObject(id) {
  const obj = { data: `Cache: ${id}` };
  registry.register(obj, id);
  return obj;
}

let cache = createCachedObject('user-123');
cache = null; // GC → 'Cache entry user-123 cleaned up'

FinalizationRegistry для очистки кэша.

**Реальный пример:**

javascript
// WeakRef cache (с проверкой)
class WeakCache {
  #cache = new Map();
  #registry = new FinalizationRegistry((key) => {
    this.#cache.delete(key);
  });

  get(key) {
    const ref = this.#cache.get(key);
    if (ref) {
      const obj = ref.deref();
      if (obj !== undefined) return obj;
      this.#cache.delete(key);
    }
    return undefined;
  }

  set(key, obj) {
    this.#cache.set(key, new WeakRef(obj));
    this.#registry.register(obj, key);
  }
}

Реальный паттерн: WeakRef cache с automatic cleanup.


Частые ошибки

**Неправильно:** Полагаться на .deref() для критических данных

**Почему:** GC может удалить объект в любой момент — .deref() вернёт undefined.

**Правильно:** WeakRef = best-effort. Не используйте для данных, которые обязаны существовать.

**Неправильно:** Думать, что FinalizationRegistry вызывается immediately

**Почему:** FinalizationRegistry callback вызывается НЕ определённо когда (после GC).

**Правильно:** FinalizationRegistry = уведомление, не гарантия.


Важно запомнить

  • WeakRef: слабая ссылка на объект
  • .deref() возвращает объект или undefined
  • FinalizationRegistry: callback при удалении
  • GC timing недетерминирован
  • Не используйте для критических данных

Связь

Назад: Вы знаете WeakMap/WeakSet (JV5). WeakRef — более низкоуровневый механизм слабых ссылок.

Вперёд: Следующий урок (JV21) — eval — выполнение строк как кода.

Материалы курса JS Advanced — PROlab Academy.