在删除元素之前,是否需要删除事件侦听器?

如果有一个父元素,其子元素与事件侦听器绑定在一起,那么在清除父元素之前,是否需要删除这些事件侦听器?(例如,parent.innerHTML = '';)如果事件侦听器没有从从 DOM 删除的元素中解除绑定,那么是否存在内存泄漏?

37260 次浏览

简短回答: yes

长话短说: 大多数浏览器都能正确地处理这个问题,并自己删除这些处理程序。有一些老的浏览器(IE6和 IE7,如果我没记错的话)搞砸了这一切。是的,可能有内存泄漏。你不用担心这个,但你需要担心。看看 this document

更新一下这里的信息。我一直在测试各种浏览器,特别是针对 iframe onload 事件的循环依赖事件侦听器的内存泄漏。

所使用的代码(jsfiddle 干扰内存测试,因此使用您自己的服务器来测试它) :

<div>
<label>
<input id="eventListenerCheckbox" type="checkbox" /> Clear event listener when removing iframe
</label>
<div>
<button id="startTestButton">Start Test</button>
</div>
</div>


<div>
<pre id="console"></pre>
</div>


<script>


(function() {
var consoleElement = document.getElementById('console');
window.log = function(text) {
consoleElement.innerHTML = consoleElement.innerHTML + '<br>' + text;
};
}());


(function() {
function attachEvent(element, eventName, callback) {
if (element.attachEvent)
{
element.attachEvent(eventName, callback);
}
else
{
element[eventName] = callback;
}
}


function detachEvent(element, eventName, callback) {
if (element.detachEvent)
{
element.detachEvent(eventName, callback);
}
else
{
element[eventName] = null;
}
}


var eventListenerCheckbox = document.getElementById('eventListenerCheckbox');
var startTestButton = document.getElementById('startTestButton');
var iframe;
var generatedOnLoadEvent;


function createOnLoadFunction(iframe) {
var obj = {
increment: 0,
hugeMemory: new Array(100000).join('0') + (new Date().getTime()),
circularReference: iframe
};


return function() {
// window.log('iframe onload called');
obj.increment += 1;
destroy();
};
}


function create() {
// window.log('create called');
iframe = document.createElement('iframe');


generatedOnLoadEvent = createOnLoadFunction(iframe);
attachEvent(iframe, 'onload', generatedOnLoadEvent);


document.body.appendChild(iframe);
}


function destroy() {
// window.log('destroy called');
if (eventListenerCheckbox.checked)
{
detachEvent(iframe, 'onload', generatedOnLoadEvent)
}


document.body.removeChild(iframe);
iframe = null;
generatedOnLoadEvent = null;
}


function startTest() {
var interval = setInterval(function() {
create();
}, 100);


setTimeout(function() {
clearInterval(interval);
window.log('test complete');
}, 10000);
}


attachEvent(startTestButton, 'onclick', startTest);
}());


</script>

如果没有内存泄漏,那么在运行测试之后,使用的内存将增加大约1000kb 或更少。但是,如果存在内存泄漏,则内存将增加约16,000 kb。首先删除事件侦听器总是会降低内存使用(没有泄漏)。

结果:

  • IE6-内存泄漏
  • IE7-内存泄漏
  • IE8-无内存泄漏
  • IE9-内存泄漏(? ? ?)
  • IE10 - memory leak (???)
  • IE11-无内存泄漏
  • Edge (20)-无内存泄漏
  • Chrome (50) - no memory leak
  • Firefox (46)-很难说,泄漏不严重,所以可能只是低效的垃圾收集器?在没有明显原因的情况下,以额外的4MB 完成。
  • Opera (36)-无内存泄漏
  • Safari (9)-无内存泄漏

结论: 前沿应用程序可能不会删除事件侦听器。但是我仍然认为这是一个很好的练习,尽管这很烦人。