Javascript: когда DOM удаляется, его прослушиватели событий также удаляются? [Дубликат]

Это означает, что ваш код использовал ссылочную переменную объекта, которая была установлена ​​в нуль (т. е. она не ссылалась на экземпляр фактического объекта).

Чтобы предотвратить ошибку, объекты, которые могут быть пустыми, должны быть протестированы для null перед тем, как использовать.

if (myvar != null)
{
    // Go ahead and use myvar
    myvar.property = ...
}
else
{
    // Whoops! myvar is null and cannot be used without first
    // assigning it to an instance reference
    // Attempting to use myvar here will result in NullReferenceException
}
32
задан Nathan Long 2 December 2010 в 18:01
поделиться

5 ответов

Функции обработчика событий подчиняются той же коллекции мусора, что и другие переменные. Это означает, что они будут удалены из памяти, когда интерпретатор определит, что нет возможности получить ссылку на эту функцию. Однако простое удаление узла не гарантирует сбор мусора. Например, возьмите этот узел и связанный с ним обработчик событий

var node = document.getElementById('test');
node.onclick = function() { alert('hai') };

Теперь удалите узел из DOM

node.parentNode.removeChild(node);

Итак, node больше не будет отображаться на вашем веб-сайте , но он явно все еще существует в памяти, как и обработчик событий

node.onclick(); //alerts hai

Пока ссылка на node все еще доступна, это связанные свойства (из которых onclick является одним) будет оставаться неповрежденным.

Теперь давайте попробуем его, не создавая оборванную переменную

document.getElementById('test').onclick = function() { alert('hai'); }

document.getElementById('test').parentNode.removeChild(document.getElementById('test'));

. В этом случае, похоже, нет никакого другого способа доступа к узлу DOM #test, поэтому когда цикл сбора мусора запускается, обработчик onclick должен быть удален из памяти.

Но это очень простой случай. Использование Javascript закрытий может значительно усложнить определение собираемости мусора. Давайте попробуем привязать несколько более сложную функцию обработчика событий к onclick

document.getElementById('test').onclick = function() {
  var i = 0;
  setInterval(function() {
    console.log(i++);
  }, 1000);

  this.parentNode.removeChild(this);
};

. Поэтому, когда вы нажимаете на #test, элемент будет немедленно удален, но через секунду, а затем каждую секунду, вы будет видеть увеличенный номер, напечатанный на вашей консоли. Узел удаляется, и дальнейшая ссылка на него невозможна, но, похоже, его части остаются. В этом случае сама функция обработчика событий, скорее всего, не сохраняется в памяти, а область ее создания.

Итак, ответ, который я предполагаю; это зависит. Если есть болтающиеся, доступные ссылки на удаленные узлы DOM, связанные с ними обработчики событий будут по-прежнему находиться в памяти вместе с остальными их свойствами. Даже если это не так, область, созданная функциями обработчика событий, все еще может использоваться и в памяти.

В большинстве случаев (и с радостью игнорируя IE6) лучше всего доверять сборщику мусора, чтобы выполнять свою работу, Javascript не является C в конце концов. Однако в таких случаях, как в последнем примере, важно написать некоторые деструкторные функции для неявной функции закрытия.

21
ответ дан MooGoo 25 August 2018 в 18:15
поделиться

Возможно, вам придется удалить эти обработчики событий.

Утечки памяти Javascript после разгрузки веб-страницы

В нашем коде, который не основан на jQuery, но некоторые прототипы deviant, у нас есть инициализаторы и деструкторы в наших классах. Мы обнаружили, что абсолютно необходимо удалить обработчики событий из объектов DOM, когда мы уничтожаем не только наше приложение, но и отдельные виджеты во время выполнения.

В противном случае мы закончим утечку памяти в IE.

Удивительно легко получить утечки памяти в IE - даже когда мы выгружаем страницу, мы должны быть уверены, что приложение «выключается» чисто, убирает все - или процесс IE будет расти с течением времени.

Изменить : Чтобы сделать это правильно, у нас есть наблюдатель событий на window для события unload. Когда это событие приходит, наша цепочка деструкторов вызывается для правильной очистки каждого объекта.

И некоторый пример кода:

/**
 * @constructs
 */
initialize: function () {
    // call superclass
    MyCompany.Control.prototype.initialize.apply(this, arguments);

    this.register(MyCompany.Events.ID_CHANGED, this.onIdChanged);
    this.register(MyCompany.Events.FLASHMAPSV_UPDATE, this.onFlashmapSvUpdate);
},

destroy: function () {

    if (this.overMap) {
        this.overMap.destroy();
    }

    this.unregister(MyCompany.Events.ID_CHANGED, this.onIdChanged);
    this.unregister(MyCompany.Events.FLASHMAPSV_UPDATE, this.onFlashmapSvUpdate);

    // call superclass
    MyCompany.Control.prototype.destroy.apply(this, arguments);
},
2
ответ дан Community 25 August 2018 в 18:15
поделиться
6
ответ дан James Kovacs 25 August 2018 в 18:15
поделиться

Не обязательно

Документация метода jQuery empty() отвечает на мой вопрос и дает мне решение моей проблемы. В нем говорится:

Чтобы избежать утечек памяти, jQuery удаляет из дочерних элементов другие конструкторы, такие как данные и обработчики событий, перед удалением самих элементов.

So : 1) если мы не сделали этого явно, мы получили бы утечки памяти, а 2) с помощью empty(), я могу избежать этого.

Поэтому я должен сделать это:

formSection.empty();
formSection.html(newContents);

Мне все еще не ясно, будет ли .html() позаботиться об этом сам по себе, но одна дополнительная строка, чтобы быть уверенной, не беспокоит меня.

2
ответ дан Nathan Long 25 August 2018 в 18:15
поделиться

Я хотел знать себя так после небольшого теста, я думаю, что ответ да.

removeEvent вызывается, когда вы .remove () что-то из DOM.

< / blockquote>

Если вы хотите увидеть его сами, вы можете попробовать это и выполнить код, установив точку останова. (Я использовал jquery 1.8.1)

Добавить новый div first: $('body').append('<div id="test"></div>') Проверить $.cache, чтобы убедиться, что к нему не добавлены события. (это должен быть последний объект). Присоедините к нему событие click: $('#test').on('click',function(e) {console.log("clicked")}); Проверьте его и посмотрите новый объект в $.cache: $('#test').click() Удалите его, и вы увидите, что объект в $.cache также исчез: $('#test').remove()

1
ответ дан user1736525 25 August 2018 в 18:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: