Каковы фактические виды использования WeakMap
структуры данных, представленной в ECMAScript 6?
Поскольку ключ слабой карты создает сильную ссылку на его соответствующее значение, гарантируя, что значение, которое было вставлено в слабую карту, никогда не исчезнет, пока его ключ еще жив, его нельзя использовать для мемо-таблиц, кэши или что-то еще, для чего вы обычно используете слабые ссылки, карты со слабыми значениями и т. д.
Мне кажется, что это:
weakmap.set(key, value);
... это просто окольный способ сказать это:
key.value = value;
Какие конкретные варианты использования я пропускаю?
javascript
ecmascript-6
weakmap
valderman
источник
источник
WeakMap
s можно использовать для обнаружения утечек памяти: stevehanov.ca/blog/?id=148Ответы:
В корне
WeakMaps предоставляют возможность расширять объекты извне, не мешая сборке мусора. Всякий раз, когда вы хотите расширить объект, но не можете, потому что он запечатан - или из внешнего источника, можно применить WeakMap.
WeakMap - это карта (словарь), в которой ключи слабы - то есть, если все ссылки на ключ потеряны и больше нет ссылок на значение - значение может быть собрано мусором. Давайте сначала покажем это на примерах, затем немного объясним и, наконец, закончим с реальным использованием.
Допустим, я использую API, который дает мне определенный объект:
Теперь у меня есть метод, который использует объект:
Я хочу отслеживать, сколько раз метод вызывался с определенным объектом, и сообщать, если это произошло более чем в N раз. Наивно можно подумать, чтобы использовать карту:
Это работает, но имеет утечку памяти - теперь мы отслеживаем каждый отдельный объект библиотеки, передаваемый в функцию, которая предотвращает сборку мусора объектами библиотеки. Вместо этого - мы можем использовать
WeakMap
:И утечка памяти исчезла.
Случаи использования
Некоторые варианты использования, которые в противном случае могли бы вызвать утечку памяти и включаются
WeakMap
с помощью s, включают:Давайте посмотрим на реальное использование
Он может быть использован для расширения объекта снаружи. Давайте приведем практический (адаптированный, в некотором роде реальный - чтобы подчеркнуть) пример из реального мира Node.js.
Допустим, вы Node.js и у вас есть
Promise
объекты - теперь вы хотите отслеживать все отклоненные в настоящий момент обещания - однако вы не хотите, чтобы они не собирались мусором, если на них не существует ссылок.Теперь вы не хотите добавлять свойства к нативным объектам по понятным причинам - так что вы застряли. Если вы сохраняете ссылки на обещания, вы вызываете утечку памяти, поскольку сборка мусора невозможна. Если вы не сохраните ссылки, вы не сможете сохранить дополнительную информацию об отдельных обещаниях. Любая схема, которая предполагает сохранение идентификатора обещания, означает, что вам нужна ссылка на него.
Введите WeakMaps
Слабые карты означают, что ключи слабые. Нет способов перечислить слабую карту или получить все ее значения. На слабой карте вы можете хранить данные, основанные на ключе, а когда ключ получает мусор, собирайте значения.
Это означает, что с помощью обещания вы можете сохранить состояние о нем, и этот объект все еще можно собирать мусором. Позже, если вы получите ссылку на объект, вы можете проверить, есть ли у вас какое-либо состояние, относящееся к нему, и сообщить об этом.
Это было использовано для реализации необработанных крюков отказов от Петька Антонов , как это :
Мы храним информацию об обещаниях на карте и можем знать, когда было выполнено отклоненное обещание.
источник
useObj
примере, использующем a,Map
а не a,WeakMap
мы используем переданный объект как ключ карты. Объект никогда не удаляется с карты (так как мы не знали бы, когда это сделать), поэтому всегда есть ссылка на него, и он никогда не может быть собран мусором. В примере WeakMap, как только все другие ссылки на объект исчезнут, объект может быть очищен отWeakMap
. Если вы все еще не уверены, что я имею в виду, пожалуйста, дайте мне знатьcalled
пример лучше написан с использованием jsfiddle.net/f2efbm7z, и он не демонстрирует использование слабой карты. Фактически, это может быть лучше написано в общей сложности 6 способами, которые я перечислю ниже.p[key_symbol] = data
, или 2) уникальное именование;p.__key = data
, или 3) частная сфера;(()=>{let data; p.Key = _=>data=_;})()
, или 4) прокси с 1 или 2 или 3. или 5) заменить / расширить класс Promise на 1, 2 или 3. или 6) заменить / расширить класс Promise с набором необходимых членов. - В любом случае, слабая карта не нужна, если вам не нужен кэш, чувствительный к памяти.Этот ответ кажется предвзятым и непригодным для сценария реального мира. Пожалуйста, прочитайте это как есть, и не рассматривайте это как актуальный вариант для чего-либо другого, кроме экспериментов
Вариант использования может быть использовать его в качестве словаря для слушателей, у меня есть сотрудник, который сделал это. Это очень полезно, потому что любой слушатель напрямую нацелен на такой способ работы. До свидания
listener.on
.Но с более абстрактной точки зрения,
WeakMap
особенно мощно дематериализовать доступ практически ко всему, вам не нужно пространство имен, чтобы изолировать его членов, поскольку это уже подразумевается природой этой структуры. Я почти уверен, что вы могли бы сделать некоторые значительные улучшения памяти, заменив неловкие избыточные ключи объектов (хотя деконструкция работает для вас).Прежде чем читать, что дальше
Теперь я понимаю, что мои акценты не совсем лучший способ решения проблемы, и, как отметил Бенджамин Грюнбаум (посмотрите его ответ, если он еще не выше моего: p), эту проблему нельзя было бы решить с помощью регулярного
Map
, так как он просочился бы, поэтому главная сила вWeakMap
том, что он не мешает сбору мусора, поскольку они не сохраняют ссылку.Вот актуальный код моего коллеги (спасибо ему за то, что поделился)
Полный источник здесь , это об управлении слушателями, о котором я говорил выше (вы также можете взглянуть на спецификации )
источник
WeakMap
хорошо работает для инкапсуляции и сокрытия информацииWeakMap
доступно только для ES6 и выше. AWeakMap
представляет собой набор пар ключ и значение, где ключ должен быть объектом. В следующем примере мы создаемWeakMap
два элемента:Мы использовали
set()
метод для определения связи между объектом и другим элементом (в нашем случае это строка). Мы использовалиget()
метод для получения элемента, связанного с объектом. Интересным аспектомWeakMap
s является тот факт, что он содержит слабую ссылку на ключ внутри карты. Слабая ссылка означает, что если объект уничтожен, сборщик мусора удалит всю запись изWeakMap
, тем самым освободив память.источник
𝗠𝗲𝘁𝗮𝗱𝗮𝘁𝗮
Слабые карты могут использоваться для хранения метаданных об элементах DOM, не мешая сбору мусора и не сводя коллег с ума от вашего кода. Например, вы можете использовать их для нумерации всех элементов веб-страницы.
𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗼𝗿 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗮𝗻𝗱 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗧𝗵𝗲 𝗗𝗶𝗳𝗳𝗲𝗿𝗲𝗻𝗰𝗲
Разница может показаться незначительной, за исключением того, что версия слабой карты длиннее, однако между двумя фрагментами кода, показанными выше, есть существенная разница. В первом фрагменте кода, без слабых отображений, фрагмент кода хранит ссылки в разные стороны между элементами DOM. Это предотвращает сборку мусора элементами DOM.
(i * i) % len
может показаться странным, что никто бы не использовал, но подумайте еще раз: во многих производственных кодах есть ссылки на DOM, которые отражаются по всему документу. Теперь для второго фрагмента кода, поскольку все ссылки на элементы являются слабыми, когда вы удаляете узел, браузер может определить, что узел не используется (не может быть достигнут вашим кодом), и таким образом удалите это из памяти. Причина, по которой вы должны быть обеспокоены использованием памяти и якорями памяти (такими как первый фрагмент кода, где неиспользуемые элементы хранятся в памяти), заключается в том, что большее использование памяти означает больше попыток GC браузера (чтобы попытаться освободить память для предотвращение сбоя браузера) означает более медленный просмотр и иногда сбой браузера.Что касается polyfill для них, я бы порекомендовал мою собственную библиотеку ( находится здесь @ github ). Это очень легкая библиотека, которая просто заполняет ее без каких-либо слишком сложных сред, которые вы можете найти в других полизаполнениях.
Счастливого кодирования!
источник
elements
на ноль, и все готово: это будет GCed. & Re: « Ссылки DOM, которые отражаются по всему документу », не имеет никакого значения: как только основная ссылкаelements
исчезнет, все циклические ссылки будут GCed. Если ваш элемент содержит ссылки на элемент, который ему не нужен, то исправьте код и установите для ref значение null, когда вы закончите с его использованием. Это будет GCed. Слабые карты не нужны .elements
на ноль не позволит браузеру собирать элементы в ситуации первого фрагмента. Это происходит потому, что вы устанавливаете пользовательские свойства для элементов, и затем эти элементы все еще могут быть получены, и к их пользовательским свойствам все равно можно получить доступ, тем самым предотвращая GC-кодирование любого из них. Думайте об этом как о цепочке металлических колец. Solongas у вас есть доступ по крайней мере к одному звену в цепочке, вы можете удерживать это звено в цепочке и, таким образом, предотвращать падение всей цепочки предметов в пропасть.Я использую
WeakMap
для кеша беспроблемное запоминание функций, которые принимают неизменяемые объекты в качестве своих параметров.Мемоизация - это причудливый способ сказать: «после того, как вы вычислите значение, кэшируйте его, чтобы вам не приходилось вычислять его снова».
Вот пример:
Показать фрагмент кода
Несколько вещей, на которые стоит обратить внимание:
источник
У меня есть этот простой основанный на функции вариант использования / Пример для WeakMaps.
УПРАВЛЯЙТЕ КОЛЛЕКЦИЕЙ ПОЛЬЗОВАТЕЛЕЙ
Я начал с
User
объектом, свойство которого включает в себяfullname
,username
,age
,gender
и метод , называемом ,print
который печатает удобочитаемое резюме других свойств.Затем я добавил карту, вызываемую
users
для сохранения коллекции нескольких пользователей, на которые указывает ключusername
.Добавление коллекции также требовало вспомогательных функций для добавления, получения, удаления пользователя и даже функции для печати всех пользователей для полноты картины.
Поскольку весь вышеприведенный код работает, скажем, в NodeJS , только
users
карта имеет ссылку на пользовательские объекты во всем процессе. Нет другой ссылки на отдельные объекты пользователя.Запустив этот код в виде интерактивной оболочки NodeJS, просто в качестве примера я добавляю четырех пользователей и печатаю их:
ДОБАВЬТЕ БОЛЬШЕ ИНФОРМАЦИИ ДЛЯ ПОЛЬЗОВАТЕЛЕЙ БЕЗ ИЗМЕНЕНИЯ СУЩЕСТВУЮЩЕГО КОДА
Теперь, скажем, требуется новая функция, в которой ссылки каждого пользователя на платформу Social Media Platform (SMP) должны отслеживаться вместе с объектами пользователя.
Ключевым моментом здесь также является то, что эта функция должна быть реализована с минимальным вмешательством в существующий код.
Это возможно с WeakMaps следующим образом.
Я добавляю три отдельных WeakMaps для Twitter, Facebook, LinkedIn.
Вспомогательная функция
getSMPWeakMap
добавляется просто для того, чтобы вернуть WeakMap, связанный с данным именем SMP.Функция для добавления SMP-ссылки пользователя к указанному SMP WeakMap.
Функция для печати только тех пользователей, которые присутствуют на данном SMP.
Теперь вы можете добавить ссылки SMP для пользователей, также с возможностью каждого пользователя иметь ссылку на несколько SMP.
... продолжая предыдущий пример, я добавляю ссылки SMP для пользователей, несколько ссылок для пользователей Билла и Сары, а затем печатаю ссылки для каждого SMP отдельно:
Теперь скажите, что пользователь удален с
users
карты по телефонуdeleteUser
. Это удаляет единственную ссылку на пользовательский объект. Это, в свою очередь, также очистит SMP-ссылку от любого / всех SMP WeakMaps (сборщиком мусора), так как без объекта User невозможно получить доступ к какой-либо из его SMP-ссылок.... продолжая Пример, я удаляю пользователя Билла, а затем распечатываю ссылки SMP, с которыми он был связан:
Не требуется никакого дополнительного кода для отдельного удаления ссылки SMP отдельно и существующего кода до того, как эта функция не была изменена в любом случае.
Если есть какой-либо другой способ добавить эту функцию с / без WeakMaps, пожалуйста, не стесняйтесь комментировать.
источник