close
Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Apply suggestions from code review
  • Loading branch information
dolgachio authored Feb 27, 2024
commit 02ad1a666dfe5cd3e9852f6e66e9baf19fc95b2d
20 changes: 13 additions & 7 deletions 1-js/99-js-misc/07-weakref-finalizationregistry/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ let user = { name: "John" };

У нашому випадку — це змінна `user`:

Comment thread
dolgachio marked this conversation as resolved.

```js
// у змінній user знаходиться сильне посилання на об'єкт
let user = { name: "John" };
Expand All @@ -84,6 +85,7 @@ let user = { name: "John" };
*!*
let admin = new WeakRef(user);
*/!*
Comment thread
dolgachio marked this conversation as resolved.

```

На схемі нижче зображено два типи посилань: сильне посилання з використанням змінної `user` і слабке посилання з використанням змінної `admin`:
Expand All @@ -108,6 +110,7 @@ user = null;

Метод `deref()` повертає об'єкт-референт, на який посилається `WeakRef`, якщо об'єкт все ще перебуває в пам'яті. Якщо об'єкт було видалено збирачем сміття, - метод `deref()` поверне `undefined`:

Comment thread
dolgachio marked this conversation as resolved.

```js
let ref = admin.deref();

Expand All @@ -123,7 +126,8 @@ if (ref) {
`WeakRef` зазвичай використовується для створення кешу або [асоціативних масивів](https://uk.wikipedia.org/wiki/Асоціативний_масив), де зберігаються великі об'єкти.
Це дозволяє уникнути перешкоджанню видаленню цих об'єктів збирачем сміття тільки на основі їхньої присутності в кеші або асоціативному масиві.

Один з основних прикладів - це ситуація, коли ми маємо велику кількість об'єктів бінарних зображень (наприклад, представлених у вигляді `ArrayBuffer` або `Blob`), і ми хочемо пов'язати ім'я або шлях з кожним зображенням. Існуючі структури даних не зовсім підходять для таких цілей:
Один з основних прикладів - це ситуація, коли ми маємо велику кількість об'єктів бінарних зображень (наприклад, представлених у вигляді `ArrayBuffer` або `Blob`), і ми хочемо пов'язати ім'я або шлях з кожним зображенням.
Існуючі структури даних не зовсім підходять для таких цілей:

- Використання `Map` для створення зв'язку між іменами та зображеннями, або навпаки, збереже об'єкти зображень у пам'яті, оскільки вони фігурують у `Map` як ключі або значення.
- `WeakMap` також не підійде в цьому випадку: через те, що об'єкти, представлені у якості ключів `WeakMap`, використовують слабкі посилання і не захищені від видалення збирачем сміття.
Expand Down Expand Up @@ -173,14 +177,14 @@ const getCachedImg = weakRefCache(fetchImg);

Давайте детально розберемо все, що тут сталося:
1. `weakRefCache` - це функція вищого порядку, яка приймає іншу функцію `fetchImg` як аргумент. У цьому прикладі ми можемо знехтувати докладним описом функції `fetchImg`, оскільки це може бути абсолютно будь-яка логіка завантаження зображень.
2. `imgCache` - це кеш зображень, який зберігає кешовані результати функції `fetchImg`, з ключами рядками (ім'я зображення) та об'єктів `WeakRef` як їх значення.
2. `imgCache` - це кеш зображень, який зберігає кешовані результати функції `fetchImg`, з ключами рядками (ім'я зображення) та об'єктами `WeakRef` як їх значення.
3. Повертаємо анонімну функцію, яка приймає ім'я зображення як аргумент. Даний аргумент буде використовуватися як ключ для кешованого зображення.
4. Намагаємося отримати кешований результат з кешу, використовуючи наданий ключ (ім'я зображення).
5. Якщо кеш містить значення за вказаним ключем, і об'єкт `WeakRef` не був видалений збирачем сміття, повертаємо кешований результат.
6. Якщо в кеші немає запису із запитаним ключем, або метод `deref()` повертає `undefined` (що означає, що об'єкт `WeakRef` було видалено збирачем сміття), функція `fetchImg` завантажує зображення заново.
6. Якщо в кеші немає запису для цього ключа, або метод `deref()` повертає `undefined` (що означає, що об'єкт `WeakRef` було видалено збирачем сміття), функція `fetchImg` завантажує зображення заново.
7. Розміщуємо завантажене зображення в кеш у вигляді `WeakRef` об'єкта.

Тепер у нас є колекція `Map`, в якій ключі це імена зображень у вигляді рядків, а значення це об'єкти `WeakRef`, що містять самі зображення.
Тепер у нас є колекція `Map`, в якій ключі - це імена зображень у вигляді рядків, а значення - це об'єкти `WeakRef`, що містять самі зображення.

Ця техніка допомагає уникнути виділення великого об'єму пам'яті на ресурсомісткі об'єкти, які більше ніхто не використовує.
Також вона заощаджує пам'ять та час у разі повторного використання кешованих об'єктів.
Expand All @@ -193,9 +197,10 @@ const getCachedImg = weakRefCache(fetchImg);

![](weakref-finalizationregistry-04.svg)

Один зі способів впоратися з цією проблемою - це періодично перевіряти кеш і видаляти "мертві" записи.
Один зі способів подолати цей недолік - це періодично перевіряти кеш і видаляти "мертві" записи.
Інший спосіб - використовувати фіналізатори, з якими ми ознайомимося далі.

Comment thread
dolgachio marked this conversation as resolved.

## Приклад №2: застосування WeakRef для відстеження об'єктів DOM

Ще один варіант використання `WeakRef` - відстеження об'єктів DOM.
Expand All @@ -209,9 +214,10 @@ const getCachedImg = weakRefCache(fetchImg);

При натисканні на кнопку "Почати відправку повідомлень", у так званому "вікні відображення логів" (елемент з класом `.window__body`) починають з'являтися написи (логи).

Але, як тільки цей елемент видалиться з DOM, логер повинен припинити надсилати повідомлення. Щоб відтворити видалення даного елемента, достатньо лише натиснути на кнопку "Закрити" у правому верхньому куті.
Але, як тільки цей елемент видалиться з DOM, логер повинен припинити надсилати повідомлення.
Щоб відтворити видалення даного елемента, достатньо лише натиснути на кнопку "Закрити" у правому верхньому куті.

Для того, щоб нам не ускладнювати роботу, і не сповіщати сторонній код кожен раз, коли наш DOM-елемент доступний, а коли ні, достатньо буде створити на нього слабке посилання за допомогою `WeakRef`.
Для того, щоб нам не ускладнювати роботу, і не сповіщати сторонній код кожен раз, коли наш DOM-елемент доступний, а коли - ні, достатньо буде створити для нього слабке посилання за допомогою `WeakRef`.

Після того як елемент буде видалено з DOM, логер це побачить і припинить надсилати повідомлення.

Expand Down