Как jQuery data() нарушает циклическую ссылку

Я прочитал, почему это лучше и как это реализовано. Но что я на самом деле не понимаю, как это нарушает круговую ссылку?,

как это разрывает контрольный круг?

$(div1).data('item', div2);
$(div2).data('item', div1);

Например, приведенные выше элементы указывают друг на друга, как это предотвратить? У меня есть догадка, но я просто хочу убедиться, что моя догадка верна.

1 ответ

Решение

Проблема циклической ссылки возникает в некоторых браузерах, когда вы помещаете ссылку на объект DOM на объект DOM как свойство этого объекта DOM. Затем у вас есть два объекта DOM, указывающих друг на друга. Удаление объекта DOM с пользовательским свойством не очищает это пользовательское свойство. Сборщик мусора, который не настолько умен, не понимает, что эта ссылка на DOM не считается, поэтому он застревает, и есть несколько способов, которые могут привести к утечкам.

.data() решает эту проблему, потому что .data() данные НЕ находятся на объекте DOM. Это просто структура данных javascript, которая может быть связана с объектом DOM через уникальный идентификатор строки.

Единственная запутанная часть этого заключается в том, что когда вы читаете .data("key") и key не найден в JavaScript .data() структура данных, тогда и только тогда, jQuery будет искать атрибут в объекте DOM, называемый "data-key", Но всякий раз, когда вы пишете с .data("key", "myData"), он никогда не пишет в объект DOM, только в структуру данных javascript.

Таким образом, так как .data() никогда не записывает данные в объект DOM, не может быть таких циклических ссылок, с которыми у некоторых браузеров возникают проблемы.

Есть несколько других полезных вещей, которые нужно знать о .data() структура данных. Когда вы используете JQuery's .remove() удалить элементы из DOM или когда вы звоните $(elem).html("new html")jQuery очищает .data() данные о любых удаленных предметах. Это один из случаев, когда хорошо не смешивать jQuery с простым javascript. Если вы используете .data(), то вы всегда должны удалять элементы из DOM, используя функции jQuery, так .data() очищен соответствующим образом. В противном случае, вы можете получить утечки памяти таким образом (оба .data() данные могут утечь, и любые удаленные объекты DOM, на которые есть ссылки в .data() может протечь. Но, если вы используете только методы jQuery для удаления элементов из DOM (включая замену innerHTML), то jQuery очистит все соответствующим образом и не будет утечек.

Так, например, это создаст утечку памяти:

// suppose elem is a DOM element reference

// store some data in jQuery's data storage on behalf of a DOM element
$(elem).data("someKey", "someValue");

// remove DOM element with plain Javascript
elem.parentNode.removeChild(elem);

Поскольку вы удалили элемент DOM с простым Javascript, у jQuery не было возможности очистить ранее сохраненные данные. Сам элемент DOM будет собираться мусором, но .data() ранее сохраненное вами значение теперь потеряно в хранилище jQuery и, по сути, является "утечкой", так как оно, вероятно, никогда не будет очищено. С другой стороны, если вы сделаете это:

$(elem).data("someKey", "someValue");
$(elem).remove();

Затем jQuery увидит, что вы удаляете элемент DOM, а также очистит данные, которые вы сохранили с .data(),

Довольно простой способ понять, как это работает, - создать сценарий из нескольких строк с не минимизированной версией jQuery, а затем просто выполнить вызов $(elem).data("key", "whatever") в отладчике и смотри как он работает.

Другие вопросы по тегам