Що робить WeakRef?
Що таке WeakRef
WeakRef (Weak Reference) - це об'єкт, який містить слабке посилання на інший об'єкт, тобто таке посилання, яке не заважає збирачу сміття видалити цей об'єкт, якщо на нього більше ніхто не посилається.
Простіше кажучи:
WeakRefдозволяє "пам'ятати" об'єкт поки він живий, але не утримувати його в пам'яті штучно.
Приклад звичайного (сильного) посилання
let user = { name: "Tim" };
let ref = user; // звичайне посилання
user = null; // але ref все ще утримує об'єкт!
console.log(ref.name); // "Tim"Об'єкт не буде видалений збирачем сміття,
поки існує хоча б одне "сильне" посилання (ref).
Приклад слабкого посилання (WeakRef)
let user = { name: "Tim" };
let weakRef = new WeakRef(user);
user = null; // тепер немає сильних посилань
// ...пізніше, можливо...
console.log(weakRef.deref()?.name); // "Tim" або undefinedТепер об'єкт може бути видалений GC у будь-який момент,
а weakRef.deref() поверне undefined, якщо об'єкт уже зібрано.
Як працює WeakRef
new WeakRef(obj)- створює слабке посилання.weakRef.deref()- намагається повернути оригінальний об'єкт (якщо він ще живий).- Якщо об'єкт уже зібрано GC,
deref()повернеundefined.
Приклад реальної поведінки
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 утримує ключі сильно:
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:
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.
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:
Об'єкт user#1 видалено з пам'яті(виклик не гарантований за часом і може взагалі не відбутись перед завершенням процесу.)
Важливо знати
| Особливість | Опис |
|---|---|
WeakRef не запобігає збиранню | об'єкт може зникнути в будь-який момент |
deref() може повернути undefined | якщо GC уже видалив об'єкт |
| Не можна "покладатись" на час життя | GC непередбачуваний |
| Не використовувати без потреби | може призвести до "зомбі"-помилок (об'єкт зник раптово) |
| Корисний лише у спец. сценаріях | кеш, мемоізація, інтеграція з GC |
Коли не варто використовувати WeakRef
Для керування звичайними даними. Щоб "пришвидшити" GC - це марно. Для зберігання станів у React/Vue/Next. У критичних логічних ланцюжках (результат може зникнути в будь-який момент).
Підсумок
| Що робить | Створює слабке посилання на об'єкт |
|---|---|
| Як працює | Не заважає GC видалити об'єкт |
| Метод | .deref() повертає об'єкт або undefined |
| Корисний для | Кешів, мемоізації, трекінгу пам'яті |
| Ризики | Об'єкт може зникнути в будь-який момент |
| З'явився у | ES2021 |
Головна ідея:
WeakRef= "посилання, яке не заважає збирачу сміття". Використовуй, коли хочеш "тримати об'єкт, але не володіти ним".
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.