Можно ли создать "слабую ссылку" в JavaScript?
Есть ли способ в javascript, чтобы создать "слабую ссылку" на другой объект? Вот вики-страница, описывающая слабую ссылку. Вот еще одна статья, которая описывает их на Java. Кто-нибудь может придумать способ реализовать это поведение в JavaScript?
11 ответов
В JavaScript нет поддержки слабых ссылок. Вы можете свернуть свой собственный, используя ручной подсчет ссылок, но не особенно плавно. Вы не можете создать объект-посредник-посредник, потому что в JavaScript объекты никогда не знают, когда они собираются собрать мусор.
Таким образом, ваша "слабая ссылка" становится ключом (например, целочисленным) в простом поиске с помощью метода add-reference и remove-reference, и когда больше нет ссылок, отслеживаемых вручную, запись может быть удалена, оставляя будущие поиски включенными этот ключ, чтобы вернуть ноль.
На самом деле это не слабая ссылка, но она может решить некоторые из тех же проблем. Обычно это делается в сложных веб-приложениях, чтобы предотвратить утечку памяти из браузеров (обычно IE, особенно более старых версий), когда существует цикл ссылок между узлом DOM или обработчиком событий и объектом, связанным с ним, таким как замыкание. В этих случаях полная схема подсчета ссылок может даже не потребоваться.
При запуске JS на NodeJS, вы можете рассмотреть https://github.com/TooTallNate/node-weak.
Обновление: сентябрь 2019 г.
Пока что невозможно использовать слабые ссылки, но, скорее всего, скоро это станет возможным, поскольку WeakRefs в JavaScript находятся в стадии разработки. Подробности ниже.
Предложение
Предложение находится в стадии 3, что означает, что оно имеет полную спецификацию и что дальнейшее уточнение потребует обратной связи от реализаций и пользователей.
Предложение WeakRef включает в себя две основные новые функциональные возможности:
- Создание слабых ссылок на объекты с помощью класса WeakRef
- Запуск определяемых пользователем финализаторов после сборки объектов с помощью класса FinalizationGroup
Случаи применения
Первичное использование слабых ссылок является реализация кэшей или отображений, занимающих крупные объекты, где Ита € ™ s желательно, чтобы большой объект не оставлял в живых только потому, что появляется в кэше или отображения.
Завершение - это выполнение кода для очистки после объекта, который стал недоступен для выполнения программы. Определяемые пользователем финализаторы позволяют использовать несколько новых вариантов использования и могут помочь предотвратить утечки памяти при управлении ресурсами, о которых сборщик мусора не знает.
Источник и дальнейшее чтение
https://github.com/tc39/proposal-weakrefs
https://v8.dev/features/weak-references
2021 Обновление
WeakRef
теперь реализован в Chrome, Edge и Firefox. Все еще ждем Safari и некоторых других противников.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef
Обновление от мая 2021 г. Теперь оно доступно в Safari, то есть во всех основных браузерах. См. Выше.
Истинных слабых ссылок нет, пока нет (но производители браузеров смотрят на эту тему). Но вот идея о том, как симулировать слабые ссылки.
Вы можете создать кеш, через который вы ведете свои объекты. Когда объект сохраняется, кэш сохраняет прогноз того, сколько памяти займет этот объект. Для некоторых элементов, таких как хранение изображений, это прямо вперед, чтобы работать. Для других это будет сложнее.
Когда вам нужен объект, вы запрашиваете кэш для него. Если в кеше есть объект, он возвращается. Если его там нет, то элемент генерируется, сохраняется, а затем возвращается.
Слабые ссылки моделируются элементами, удаляющими кэш, когда общий объем прогнозируемой памяти достигает определенного уровня. Он будет прогнозировать, какие элементы наименее используются, исходя из того, как часто они извлекаются, с учетом того, как давно они были изъяты. Можно также добавить стоимость вычисления, если код, который создает элемент, передается в кеш как замыкание. Это позволило бы кешу хранить элементы, которые очень дорого строить или генерировать.
Алгоритм удаления является ключевым, потому что, если вы ошибетесь, вы можете удалить самые популярные элементы. Это приведет к ужасной производительности.
Пока кеш является единственным объектом с постоянными ссылками на сохраненные объекты, вышеупомянутая система должна работать довольно хорошо как альтернатива истинным слабым ссылкам.
Просто для справки; В JavaScript его нет, но в ActionScript 3 (который также является ECMAScript). Проверьте параметр конструктора для словаря.
Использование механизма кэширования для эмуляции слабой ссылки, как предложено выше в JL235, является разумным. Если бы слабые ссылки существовали изначально, вы бы наблюдали такое поведение:
this.val = {};
this.ref = new WeakReference(this.val);
...
this.ref.get(); // always returns val
...
this.val = null; // no more references
...
this.ref.get(); // may still return val, depending on already gc'd or not
Тогда как с кешем вы бы наблюдали:
this.val = {};
this.key = cache.put(this.val);
...
cache.get(this.key); // returns val, until evicted by other cache puts
...
this.val = null; // no more references
...
cache.get(this.key); // returns val, until evicted by other cache puts
Как владелец ссылки, вы не должны делать какие-либо предположения о том, когда она ссылается на значение, это не отличается при использовании кэша
Наконец-то они здесь. Еще не реализовано в браузерах, но скоро будет.
предложение и некоторые детали https://github.com/tc39/proposal-weakrefs
Копировать/вставить машинописную версию
export class IterableWeakMap<T extends Object, V> {
weakMap = new WeakMap();
refSet = new Set<WeakRef<T>>();
finalizationGroup = new FinalizationRegistry(IterableWeakMap.cleanup);
static cleanup({ set, ref }: { set: Set<WeakRef<Object>>; ref: WeakRef<Object> }) {
set.delete(ref);
}
constructor(iterable?: Iterable<[T, V]>) {
if (!iterable) return;
for (const [key, value] of iterable) {
this.set(key, value);
}
}
set(key: T, value: V) {
const ref = new WeakRef<T>(key);
this.weakMap.set(key, { value, ref });
this.refSet.add(ref);
this.finalizationGroup.register(key, { set: this.refSet, ref }, ref);
}
get(key: T) {
const entry = this.weakMap.get(key);
return entry && entry.value;
}
delete(key: T) {
const entry = this.weakMap.get(key);
if (!entry) {
return false;
}
this.weakMap.delete(key);
this.refSet.delete(entry.ref);
this.finalizationGroup.unregister(entry.ref);
return true;
}
*[Symbol.iterator]() {
for (const ref of this.refSet) {
const key = ref.deref();
if (!key) continue;
const { value } = this.weakMap.get(key);
yield [key, value];
}
}
entries() {
return this[Symbol.iterator]();
}
*keys() {
for (const [key] of this) {
yield key;
}
}
*values() {
for (const [, value] of this) {
yield value;
}
}
}
EcmaScript 6 (ES Harmony) имеет объект WeakMap. Поддержка браузеров среди современных браузеров довольно хороша (последние 3 версии Firefox, Chrome и даже будущая версия IE поддерживают это).
http://www.jibbering.com/faq/faq_notes/closures.html
ECMAScript использует автоматическую сборку мусора. Спецификация не определяет детали, оставляя это на усмотрение разработчиков, и известно, что некоторые реализации дают очень низкий приоритет своим операциям по сборке мусора. Но общая идея заключается в том, что если объект становится нереакционноспособным (из-за отсутствия оставшихся ссылок на него доступным для выполнения кода), он становится доступным для сборки мусора и в какой-то момент в будущем будет уничтожен, а любые ресурсы, которые он потребляет, будут освобождены и возвращены в систему для повторного использования.
Обычно это происходит при выходе из контекста исполнения. Структура цепочки областей действия, объект Activation/Variable и любые объекты, созданные в контексте выполнения, включая объекты функций, больше не будут доступны и, следовательно, станут доступны для сборки мусора.
Это означает, что нет слабых, только те, которые больше не становятся доступными.