Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що робить WeakRef?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)`WeakRef` **(Weak Reference)** - це об'єкт, який містить слабке посилання на інший об'єкт, тобто таке посилання, яке не заважає збирачу сміття видалити цей об'єкт, якщо на нього більше ніхто не посилається. **Ключове:** `WeakRef` дозволяє "пам'ятати" об'єкт, поки він живий, але не утримувати його в пам'яті штучно.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення## Що таке WeakRef `WeakRef` **(Weak Reference)** - це об'єкт, який містить **слабке посилання на інший об'єкт**, тобто таке посилання, яке **не заважає збирачу сміття видалити цей об'єкт**, якщо на нього більше ніхто не посилається. Простіше кажучи: > `WeakRef` дозволяє "пам'ятати" об'єкт **поки він живий**, > але **не утримувати його в пам'яті** штучно. ## Приклад звичайного (сильного) посилання ```javascript let user = { name: "Tim" }; let ref = user; // звичайне посилання user = null; // але ref все ще утримує об'єкт! console.log(ref.name); // "Tim" ``` Об'єкт **не буде видалений збирачем сміття**, поки існує хоча б одне "сильне" посилання (`ref`). ## Приклад слабкого посилання (WeakRef) ```javascript let user = { name: "Tim" }; let weakRef = new WeakRef(user); user = null; // тепер немає сильних посилань // ...пізніше, можливо... console.log(weakRef.deref()?.name); // "Tim" або undefined ``` Тепер об'єкт може бути **видалений GC у будь-який момент**, а `weakRef.deref()` поверне `undefined`, якщо об'єкт уже зібрано. ## Як працює WeakRef 1. `new WeakRef(obj)` - створює слабке посилання. 2. `weakRef.deref()` - намагається повернути оригінальний об'єкт (якщо він ще живий). 3. Якщо об'єкт уже зібрано GC, `deref()` поверне `undefined`. ## Приклад реальної поведінки ```javascript let ref; (() => { let bigObject = { data: "Some heavy data..." }; ref = new WeakRef(bigObject); })(); // bigObject більше не досяжний напряму setTimeout(() => { console.log(ref.deref()); // або об'єкт, або undefined - залежить від GC }, 1000); ``` Збирач сміття запускається **у невизначений момент**. Не можна передбачити, коли `deref()` почне повертати `undefined`. ## Навіщо потрібен WeakRef Зазвичай у JS **не потрібно** дбати про ручне керування пам'яттю. Але є вузькі випадки, коли `WeakRef` корисний: | Сценарій | Приклад | |---|---| | **Кешування без витоків** | Хочеш кешувати об'єкти, але не утримувати їх у пам'яті "вічно" | | **Мемоізація** | Наприклад, зберігати результат обчислення для об'єкта, поки він живий | | **Реактивні системи / спостерігачі** | Стежити за об'єктом, але не заважати його збиранню | | **Ігрові рушії / графіка** | Кешувати важкі ресурси (текстури, дані), але дозволяти GC очищати їх | | **Інтеграція з FinalizationRegistry** | Реагувати, коли об'єкт зібрано GC | ## Приклад: кеш без витоків Звичайний Map утримує ключі сильно: ```javascript const cache = new Map(); function getUserData(user) { if (!cache.has(user)) { cache.set(user, heavyCompute(user)); } return cache.get(user); } ``` Проблема: навіть якщо `user` більше не потрібен, `Map` **не дасть GC видалити його**, поки кеш не очиститься вручну. Рішення - використовувати `WeakRef` та `FinalizationRegistry`: ```javascript const cache = new Map(); function getUserData(user) { const ref = cache.get(user); let data = ref?.deref(); if (!data) { data = heavyCompute(user); cache.set(user, new WeakRef(data)); } return data; } ``` Тепер якщо `data` більше ніде не використовується, GC її звільнить, і `ref.deref()` просто поверне `undefined`. ## Зв'язка з FinalizationRegistry Щоб дізнатись, **коли об'єкт було зібрано GC**, використовують `FinalizationRegistry`. ```javascript const registry = new FinalizationRegistry(id => { console.log(`Об'єкт ${id} видалено з пам'яті`); }); let user = { name: "Tim" }; registry.register(user, "user#1"); let ref = new WeakRef(user); user = null; ``` Коли GC збере `user`, викличеться callback: ```javascript Об'єкт user#1 видалено з пам'яті ``` (виклик не гарантований за часом і може взагалі не відбутись перед завершенням процесу.) ## Важливо знати | Особливість | Опис | |---|---| | `WeakRef` не запобігає збиранню | об'єкт може зникнути в будь-який момент | | `deref()` може повернути `undefined` | якщо GC уже видалив об'єкт | | Не можна "покладатись" на час життя | GC непередбачуваний | | Не використовувати без потреби | може призвести до "зомбі"-помилок (об'єкт зник раптово) | | Корисний лише у спец. сценаріях | кеш, мемоізація, інтеграція з GC | ## Коли не варто використовувати WeakRef Для керування звичайними даними. Щоб "пришвидшити" GC - це марно. Для зберігання станів у React/Vue/Next. У критичних логічних ланцюжках (результат може зникнути в будь-який момент). ## Підсумок | Що робить | Створює слабке посилання на об'єкт | |---|---| | Як працює | Не заважає GC видалити об'єкт | | Метод | `.deref()` повертає об'єкт або `undefined` | | Корисний для | Кешів, мемоізації, трекінгу пам'яті | | Ризики | Об'єкт може зникнути в будь-який момент | | З'явився у | ES2021 | **Головна ідея:** > `WeakRef` = "посилання, яке не заважає збирачу сміття". > Використовуй, коли хочеш *"тримати об'єкт, але не володіти ним"*.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.