Нужно ли удалять прослушиватели событий Javascript перед удалением элемента, к которому они прикреплены?
-
16-09-2019 - |
Вопрос
Предположим, я прикрепил множество прослушивателей событий к различным элементам формы.Позже я хочу удалить всю форму.
Необходимо ли (или рекомендуется) отменить регистрацию обработчиков событий, существующих в форме и ее элементах?Если да, то как проще всего удалить всех прослушивателей из коллекции элементов?Каковы последствия невыполнения этого требования?Я использую Prototype, если это имеет значение.
Вот что я на самом деле делаю.У меня есть простая форма, например:
<form id="form">
<input type="text" id="foo"/>
<input type="text" id="bar"/>
</form>
Я наблюдаю различные события на входах, например:
$('foo').observe('keypress', onFooKeypress);
$('bar').observe('keypress', onBarKeypress);
и т. д.
Форма отправляется через AJAX, а ответом является новая копия формы.Я заменяю старую форму копией новой, делая что-то вроде $('form').replace(newForm)
.Я накапливаю кучу мусора, связанного с событиями?
Решение
Да, немного.Недостаточно, чтобы стать огромной проблемой, но в таких обстоятельствах старые версии IE будут утекать.
Начиная с Prototype 1.6.1 (в настоящее время это последний вариант выпуска), библиотека выполняет эту очистку при выгрузке страницы.Когда вы используете Prototype для добавления наблюдателя событий, он сохраняет ссылку на этот элемент в массиве;при выгрузке страницы он проходит через этот массив и удаляет всех ваших наблюдателей.
Однако, если пользователь собирается оставаться на этой странице какое-то время, использование памяти будет накапливаться в течение срока службы страницы.У вас есть несколько вариантов:
Прослушивайте события на предок формы, которая никогда не заменяется.Затем в своем обработчике проверьте, откуда пришло событие.(т. е. «делегирование мероприятия»)
Явно отмените регистрацию всех ваших звонков перед звонком
Element#replace
.В вашем примере вы бы сделали:$('foo', 'bar').each(Element.stopObserving);
Это эквивалентно вызову stopObserving
без аргументов, что приводит к удалению все обработчики данного элемента.
Я бы рекомендовал вариант 1.
(Мы говорили об автоматическом удалении прослушивателя в будущей версии Prototype как часть Element#update
и Element#replace
, но это компромисс в производительности.)
Другие советы
События, которые не были отменены, не могут автоматически освободить свою память.Это особенно проблема в старых версиях IE.
Раньше в прототипе для этого использовалась автоматическая система сбора мусора, но в версии 1.6 этот метод был удален.Это задокументировано здесь.Означает ли удаление метода, что сборка мусора больше не осуществляется, или метод просто больше не является общедоступным, я не знаю.Также обратите внимание, что он вызывался только при выгрузке страницы, а это означает, что если ваши пользователи остаются на одной и той же странице в течение длительного времени, выполняя большое количество обновлений AJAX и DOM, утечка памяти может быть неприемлемой даже во время этого посещения одной страницы.
Всегда полезно удалить любые прослушиватели событий из элементов, удаленных из DOM, в случае сценария, упомянутого ниже Джонасом.