В статье, которую я недавно написал, ES 6 - быстрый взгляд на слабые карты , я объяснил, как jQuery может сделать data()
утечкой.Он в основном генерирует имя свойства expando, jQuery.expando
.Когда вы присоединяете данные к элементу, данные помещаются во внутренний массив кеша, и элементу присваивается свойство expando со значением индекса данных в кеше.Что-то похожее на это:
element[jQuery.expando] = elementId;
Способ предотвращения циклических ссылок состоит в том, чтобы не прикреплять объекты непосредственно к элементам в качестве расширений.Если ссылка на элемент остается в коде, то этот элемент не может быть удален, даже если он удален из DOM.Однако предотвращение циклических ссылок не полностью закрывает утечку - в массиве остаются данные, если элемент удаляется из DOM и собирается мусор.Таким образом, jQuery очищает массив при выгрузке страницы, а также удаляет данные из массива, если элементы удаляются из DOM, используя свои собственные методы, такие как remove()
.Он поддерживает данные в течение detach()
.
. Причина, по которой jQuery делает это, заключается в том, что нет слабого эквивалента карты, это как бы мерцание в ES 5, но не в ES 3. Как объяснялось в моей статье,WeakMap
создан именно для такой ситуации, но единственная доступная реализация - в Firefox 6 и выше, и, поскольку спецификация не завершена, даже это не должно использоваться в производственных средах.
ДругоеИз моей статьи следует отметить, что некоторые элементы не позволят вам присоединить свойства expando - <object>
и <embed>
являются двумя виновниками, названными и опозоренными в исходном коде jQuery.Для этих элементов вы в значительной степени облажались, и jQuery просто не позволит вам использовать data
для них.
Основные циклические утечки памяти ссылок происходят в реализациях с подсчетом ссылок, когда два свойства объекта содержат прямые ссылки друг на друга.Поэтому DOMObject содержит ссылку на JSObject и наоборот.Предполагая, что нет никаких других ссылок ни на один объект, у них обоих будет постоянный счетчик ссылок, равный 1, и GC не пометит их для сбора.
Старые браузеры (IE6) не нарушали бы эти циклические ссылки даже при выгрузке страницы, в то время как более новые браузеры могут ломать многие из этих циклических ссылок, распознавая вызывающие их шаблоны.jQuery.cache
и подобные шаблоны частично устраняют утечки памяти, потому что DOMObject никогда не содержит ссылку на JSObject , поэтому даже когда JSObject содержит ссылку на DOMObject , GC может пометить JSObject для сбора, когда на него больше нет ссылок.Как только GC соберет JSObject , счетчик ссылок для DOMObject будет уменьшен, что освободит его для сбора также.
Хотя IE 8+ и другие браузеры с подсчетом ссылокможет быть в состоянии сломать много круговых эталонных шаблонов (около 400 были исправлены для IE 8), вероятность утечек только уменьшается.Например, я столкнулся с огромной утечкой в одном из моих собственных приложений в IE 8 при работе с элементами скрипта и JSONP.Лучшее решение - спланировать худшее, а без WeakMap()
лучшее, что вы можете сделать, - это использовать шаблон данных jQuery.Конечно, вы рискуете получить осиротевшие предметы, но это меньшее из двух зол.