Отключить встроенные события javascript из элементов HTML в памяти
Как полностью отменить встроенные события javascript из своих HTML-элементов?
Я пробовал:
- undelegating событие из элемента body
- отключение события от элемента
- и даже удаление атрибута события из элемента HTML
К моему удивлению, только удаление атрибута onchange
(.removeAttr('onchange')
) смогло предотвратить повторное срабатывание события.
<input type="text" onchange="validateString(this)"></input>
Я знаю, что это возможно с делегатами, и это, вероятно, лучший способ, но просто играйте здесь. Этот пример является чисто гипотетическим только для того, чтобы предложить вопрос.
Итак, гипотетическая ситуация такова:
Я пишу библиотеку проверки javascript, в которой события javascript привязаны к полям ввода через встроенные атрибуты HTML:
<input type="text" onchange="validateString(this)"></input>
Но я хотел бы немного улучшить библиотеку, отменив мои события, так что людям, работающим с этой библиотекой в одностраничном приложении, не нужно управлять моими обработчиками событий и чтобы они не должны загромождать свой код вообще, проводя входные события в функции в моей гипотетической библиотеке проверки... что угодно. Ничего подобного, но это похоже на приличную работу.
Здесь "примерный" код гипотетической валидации Library.js:
Чтобы протестировать, просто введите текстовое поле, а затем щелкните в другом месте, чтобы запустить событие изменения. Сделайте это при открытии и записи веб-инспектора на вкладке "Временная шкала". Выделите область временной шкалы, которая коррелирует с тем, когда вы уволили событие изменения (запустите событие изменения несколько раз), и вы увидите, что прослушиватели событий (в окне ниже) увеличиваются на 100 в каждом событии изменения. Если управление и удаление должным образом, каждый прослушиватель событий будет правильно удален до рендеринга нового ввода, но я не нашел способ правильно сделать это с помощью встроенных событий javascript.
Что делает этот код:
- onChange, входной элемент запускает функцию проверки
- Эта функция проверяет ввод и окрашивает границу, если успешно
-
Затем через 1 секунду (чтобы продемонстрировать утечку памяти) элемент ввода заменяется одинаковым HTML 100 раз подряд, не отменяя событие изменения (потому что я не знаю, как это сделать.., что проблема здесь). Это имитирует изменение вида в одностраничном приложении. Это создает 100 новых eventListeners в DOM, которые видны через веб-инспектора.
- Интересное примечание.
$('input').removeAttr('onchange');
фактически предотвратит запуск события onchange, но не делает мусорный сбор материала eventListener/DOM, который отображается в веб-инспекторе.
Этот снимок экрана после срабатывания события изменения 3 раза. Каждый раз 100 новых узлов DOM отображаются с одинаковым HTML, и я пытаюсь отменить событие onchange
из каждого node перед заменой HTML.
![enter image description here]()
Обновление: Я вернулся к этому вопросу и просто сделал небольшой тест с помощью JSFiddle, чтобы убедиться, что ответ действительно. Я запускал "тест" десятки раз, а затем ждал - уверен, GC прошел и позаботился о бизнесе.
![enter image description here]()
Ответы
Ответ 1
Я не думаю, что тебе есть о чем беспокоиться. Хотя памяти больше нельзя ссылаться и в конечном итоге будет собирать мусор, она все равно появляется в окне памяти Web Inspector. Память будет собираться мусором, когда GC решает собрать мусор (например, когда в браузере недостаточно памяти или после некоторого фиксированного времени). Подробная информация зависит от разработчика GC. Вы можете проверить это, просто нажав кнопку "Собрать мусор" в нижней части окна Web Insepctor. Я запускаю Chrome 23, и после ввода текста в поле проверки около 5 или 6 раз, использование памяти рушится, видимо, из-за сбора мусора.
Это явление не характерно для встроенных событий. Я видел подобный шаблон, просто многократно выделяя большой массив, а затем переписывая ссылку на этот большой массив, оставляя много осиротевшей памяти для GC. Память на некоторое время замедляется, затем GC запускается и выполняет свою работу.
Ответ 2
Мой первый sggestion должен был использовать off('change')
, но, похоже, вы уже это пробовали. Возможно, причина, по которой он не работает, заключается в том, что обработчик не был привязан к .on('change')
. Я не слишком много знаю о том, как jQuery обрабатывает прослушиватель, как это внутренне, но попробуйте подключиться с помощью .on('change', function ()...
или .bind('change', function ()...
.