Відповіді:
Простий JavaScript
Якщо вилучений елемент DOM не має посилання (немає посилань на нього), то так - сам елемент збирається сміттєзбірником, а також будь-якими обробниками подій / слухачами, пов'язаними з ним.
var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
b = null;
// A reference to 'b' no longer exists
// Therefore the element and any event listeners attached to it are removed.
Однак; якщо є посилання, які все ще вказують на зазначений елемент, елемент і його слухачі подій зберігаються в пам'яті.
var a = document.createElement('div');
var b = document.createElement('p');
// Add event listeners to b etc...
a.appendChild(b);
a.removeChild(b);
// A reference to 'b' still exists
// Therefore the element and any associated event listeners are still retained.
jQuery
Справедливо було б припустити, що відповідні методи в jQuery (такі як remove()
) будуть функціонувати точно так само (зважаючи на те, що remove()
було написано, removeChild()
наприклад).
Однак це неправда ; бібліотека jQuery насправді має внутрішній метод (який є бездокументованим і теоретично його можна змінити в будь-який час), який називається cleanData()
(ось як виглядає цей метод ), який автоматично очищає всі дані / події, пов'язані з елементом після видалення з DOM (будь це через. remove()
, empty()
, і html("")
т.д.).
Як відомо, у старих браузерах, зокрема в старих версіях IE, виникають проблеми з витоком пам'яті через те, що слухачі подій зберігають посилання на елементи, до яких вони були приєднані.
Якщо ви хочете отримати більш поглиблене пояснення причин, шаблонів та рішень, які використовуються для виправлення застарілих витоків пам'яті версії IE, я повністю рекомендую вам прочитати цю статтю MSDN про розуміння та вирішення шаблонів протікання Internet Explorer.
Ще кілька статей, що стосуються цього:
Вручну вилучати слухачів вручну, мабуть, буде хорошою звичкою вступати в цьому випадку (лише якщо пам'ять є життєво важливою для вашої програми та ви фактично орієнтуєтесь на такі браузери).
remove
методу. більшу частину часу DOM просто стирається повністю. (наприклад, турбопосилання або щось таке). Мені цікаво, як впливає на пам'ять, якщо я роблю document.body.innerHTML = ''
...
стосовно jQuery:
метод .remove () виймає елементи з DOM. Використовуйте .remove (), коли ви хочете видалити сам елемент, а також все, що знаходиться всередині нього. Крім самих елементів, всі пов'язані події та дані jQuery, пов'язані з елементами, видаляються. Щоб видалити елементи, не видаляючи дані та події, скористайтеся .detach ().
Довідка: http://api.jquery.com/remove/
jQuery v1.8.2 .remove()
вихідний код:
remove: function( selector, keepData ) {
var elem,
i = 0;
for ( ; (elem = this[i]) != null; i++ ) {
if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
if ( !keepData && elem.nodeType === 1 ) {
jQuery.cleanData( elem.getElementsByTagName("*") );
jQuery.cleanData( [ elem ] );
}
if ( elem.parentNode ) {
elem.parentNode.removeChild( elem );
}
}
}
return this;
}
очевидно, використовує jQuery node.removeChild()
Відповідно до цього: https://developer.mozilla.org/en-US/docs/DOM/Node.removeChild ,
The removed child node still exists in memory, but is no longer part of the DOM. You may reuse the removed node later in your code, via the oldChild object reference.
тобто слухачі подій можуть бути видалені, але node
все ще існує в пам'яті.
removeChild
. І те й інше повертає вам посилання, яке ви можете продовжувати повторно приєднувати до останнього (у такому випадку це, очевидно, залишається в пам’яті) або викинути (у такому випадку він зрештою підхоплюється GC та видаляється).
Не соромтеся дивитись купу, щоб побачити витоки пам'яті у обробниках подій, зберігаючи посилання на елемент із закриттям, а елемент зберігає посилання на обробник події.
Збирач сміття не любить кругових посилань.
Звичайний випадок витоку пам’яті: допустити, що об’єкт має посилання на елемент. Цей елемент має посилання на обробник. І обробник має посилання на об'єкт. Об'єкт має відповідність для багатьох інших об'єктів. Цей об’єкт був частиною колекції, яку, на вашу думку, ви викинули, не віднісши її до своєї колекції. => весь об'єкт і все, на що він посилається, залишаться в пам'яті до виходу зі сторінки. => вам потрібно подумати про повний метод вбивства для вашого класу об'єктів або, наприклад, довірити рамку mvc.
Крім того, не соромтеся використовувати частину інструменту, що зберігає дерево, у інструментах для розробників Chrome.
Просто розширення інших відповідей ...
Делеговані обробники подій не будуть видалені після видалення елемента.
$('body').on('click', '#someEl', function (event){
console.log(event);
});
$('#someEL').remove(); // removing the element from DOM
Тепер перевірте:
$._data(document.body, 'events');
Щодо того jQuery
, наступні поширені методи також видалять інші конструкції, такі як обробники даних та подій:
Крім самих елементів, всі пов'язані події та дані jQuery, пов'язані з елементами, видаляються.
Щоб уникнути витоку пам'яті, jQuery видаляє інші конструкції, такі як обробники даних та події з дочірніх елементів, перш ніж видаляти самі елементи.
Крім того, jQuery видаляє інші конструкції, такі як обробники даних та події з дочірніх елементів, перш ніж замінити ці елементи новим вмістом.
Так, сміттєзбирач також видалить їх. Не завжди може бути справа зі застарілими браузерами.