Qo'shimcha mavzular

WeakRef va FinalizationRegistry

Odatda obyektga havola bo'lsa, u xotirada saqlanadi โ€” axlat yig'uvchi (garbage collector) uni o'chirmaydi. WeakRef esa zaif havola yaratadi: u obyekt yashashini kafolatlamaydi, shuning uchun kerak bo'lganda obyekt xotiradan tozalanishi mumkin.

Odatiy (kuchli) havola muammosi

Oddiy havola obyektni "ushlab turadi". Kesh (cache) yasaganda bu muammo: keshdagi obyekt boshqa hech kimga kerak bo'lmasa ham, kesh uni ushlab turgani uchun xotira bo'shamaydi.

WeakRef shu muammoni yechadi โ€” u obyektga ushlab turmaydigan havola beradi.

let obyekt = { data: "katta ma'lumot" };
let zaifHavola = new WeakRef(obyekt);

// obyektga murojaat qilish uchun deref() ishlatiladi
let olingan = zaifHavola.deref();
WeakMap/WeakSetdan farqi: ular butun kolleksiyani zaiflashtiradi, WeakRef esa bitta obyektga nozik nazorat beradi.

deref() metodi

Zaif havoladan obyektni olish uchun deref() chaqiriladi. Agar obyekt hali xotirada bo'lsa โ€” o'zini qaytaradi; allaqachon tozalangan bo'lsa โ€” undefined:

let havola = new WeakRef({ name: "Ali" });

let obyekt = havola.deref();
if (obyekt !== undefined) {
  // obyekt hali mavjud, ishlatsa bo'ladi
  console.log(obyekt.name);
} else {
  // obyekt tozalangan
  console.log("Obyekt yo'q qilingan");
}
Har safar deref() chaqirganda natijani albatta tekshiring. U istalgan vaqtda undefined qaytarishi mumkin โ€” hech qachon obyekt mavjudligiga ishonch bilan yondashmang.

Kesh misoli

WeakRefning tipik qo'llanishi โ€” xotirani band qilmaydigan kesh. Quyida rasmlarni keshlash misoli: agar keshdagi obyekt hali xotirada bo'lsa, uni qayta ishlatamiz; bo'lmasa qaytadan yaratamiz.

let kesh = new Map();

function rasmOlish(nom) {
  let havola = kesh.get(nom);
  let rasm = havola ? havola.deref() : undefined;

  if (rasm === undefined) {
    // yo'q yoki tozalangan - qaytadan yaratamiz
    rasm = { nom: nom, data: "...og'ir ma'lumot..." };
    kesh.set(nom, new WeakRef(rasm));
  }

  return rasm;
}

let a = rasmOlish("logo.png");
let b = rasmOlish("logo.png");
// a va b bir xil obyekt (kesh ishladi)

Bu keshning afzalligi: agar tizimga xotira kerak bo'lsa, keshdagi ishlatilmayotgan rasmlar avtomatik tozalanadi. Kamchiligi: Map ichida bo'sh WeakReflar qolib ketishi mumkin โ€” ularni tozalash uchun FinalizationRegistry kerak.

FinalizationRegistry

FinalizationRegistry โ€” obyekt axlat yig'uvchi tomonidan yo'q qilingach, tozalash funksiyasini (callback) chaqirish imkonini beradi. U shunday yaratiladi:

let registry = new FinalizationRegistry((qiymat) => {
  // obyekt yo'q qilingach chaqiriladi
  console.log("Tozalandi: " + qiymat);
});

Kuzatiladigan obyektni register orqali ro'yxatga olamiz. Ikkinchi argument โ€” obyekt yo'q qilingach callbackka uzatiladigan qiymat (odatda kalit yoki nom):

let obyekt = { name: "Ali" };

registry.register(obyekt, "Ali-obyekti");

// obyektga havola yo'qolgach va u tozalangach,
// callback "Ali-obyekti" bilan chaqiriladi

Yuqoridagi kesh misolini FinalizationRegistry bilan to'ldirib, tozalangan obyektning "bo'sh" yozuvini Mapdan ham o'chirib tashlaymiz:

let kesh = new Map();

let registry = new FinalizationRegistry((nom) => {
  // obyekt tozalandi -> Map'dan ham o'chiramiz
  let havola = kesh.get(nom);
  if (havola && havola.deref() === undefined) {
    kesh.delete(nom);
  }
});

function saqlash(nom, obyekt) {
  kesh.set(nom, new WeakRef(obyekt));
  registry.register(obyekt, nom);
}

Ehtiyotkorlik

WeakRef va FinalizationRegistry โ€” kuchli, ammo nozik vositalar. Ularni ehtiyotkorlik bilan ishlating:

Spetsifikatsiyaga ko'ra, FinalizationRegistry callbacki umuman chaqirilmasligi ham mumkin โ€” masalan, dastur tugab qolsa. Shuning uchun unga tayanib fayl yopish yoki tarmoq ulanishini uzish kabi zarur amallarni bajarmang.
Ko'p hollarda oddiy WeakMap yoki WeakSet yetarli va xavfsizroq. WeakRef/FinalizationRegistryga faqat chindan nozik xotira nazorati kerak bo'lgandagina murojaat qiling.

Xulosa