Я пытаюсь создать шаблон наблюдатель в JavaScript (он может существовать в стандартной библиотеке, но я хочу реализовать свой собственный).
Мне нужен контейнер слабых ссылок, чтобы убедиться, что слушатели не загружают неиспользуемые функции. Я могу использовать WeakSet для этого, однако WeakSet не может быть повторен, поэтому я не могу использовать for (let l in listeners) и информировать своих слушателей об изменении.
Что я могу сделать, чтобы решить эту проблему? На других языках, таких как Lua, Java, C и т. д., У меня нет проблем с этим.
Я не использую никаких внешних библиотек.
const makeObservable = function(obj, value)
{
// Must be a container of weak references.
// But a weakset is not sufficient.
const listeners = new Set();
obj.addListener = function(listener)
{
listeners.add(listener);
};
obj.removeListener = function(listener)
{
listeners.remove(listener);
};
obj.setValue = function(newVal)
{
if (value === newVal) return;
const oldVal = value;
value = newVal;
for (let l of listeners)
{
// Notify all listeners of the change.
l(oldVal, newVal);
}
};
obj.getValue = function()
{
return value;
};
return obj;
};
const obs1 = makeObservable({ }, 5);
const obs2 = makeObservable({ }, 10);
(function()
{
const memory = { };
const lis = function(_, newVal)
{
memory.changed = newVal;
};
// Whenever either changes, update memory.
obs1.addListener(lis);
obs2.addListener(lis);
})();
// 'memory' is out of scope, but still has references pointing to it.
// I have no current way of removing the memory leak until obs1 and obs2 fall out of scope.
В других языках есть итерируемые контейнеры слабых ссылок, такие как Lua (x = setmetatable({ }, { __mode = "k" }) или Java WeakHashMap. Кэш LRU, например, не удаляет элементы, когда они выпадают из области видимости, только когда в контейнер добавляется новый элемент. Это только уменьшит утечку памяти. , не избавляйся от них.
JS этого не поддерживает.
@Hatefiend На других языках есть ... JavaScript - это не другие языки. Берги прав.
@PatrickRoberts Bergi Есть ли способ подражать этому?
@Hatefiend no. Любая попытка создать итеративную ссылку приведет к тому, что по определению сделает ее сильной ссылкой в спецификации ECMAScript.
@PatrickRoberts, я понимаю. Полагаю, это означает, что для достижения того, что у меня есть, мне нужно быть очень внимательным к removeListener, чтобы предотвратить утечки памяти?
Код пользователя должен отвечать за явный вызов removeListener до того, как ссылка на функцию выпадет из области действия кода пользователя.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Если вы можете повторить его, это не слабая ссылка. Возможно, вы захотите погуглить, используя ключевое слово «javascript cache npm» или что-то в этом роде. WeakMaps - это не то же самое, что кеши, и кеши необходимо будет вручную собирать мусором на основе таких критериев, как LFU или LRU.