我是否需要删除事件监听器?
如果我有一个具有绑定了事件监听器的子代的父元素,在清除父代之前是否需要删除这些事件监听器? (即, parent.innerHTML = '';
)如果事件侦听器没有从元素中解除绑定(如果从DOM中移除),是否会有内存泄漏?
简短的回答: 是的
长的答案:大多数浏览器正确地处理这个并且自己删除那些处理程序。 有一些旧的浏览器(IE 6和7,如果我记得正确),这是搞砸了。 是的,可能会有内存泄漏。 你不必担心这个,但是你需要。 看看这个文件 。
只是在这里更新信息。 我一直在testing各种浏览器,专门针对iframe onload事件上的循环依赖事件侦听器的内存泄漏。
使用的代码(jsfiddle干扰内存testing,所以使用你自己的服务器来testing):
<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>
如果没有内存泄漏,testing运行后使用的内存将增加大约1000kb或更less。 但是,如果有内存泄漏,内存将增加约16,000kb。 首先删除事件监听器总是会导致内存使用率降低(无泄漏)。
结果:
- IE6 – 内存泄漏
- IE7 – 内存泄漏
- IE8 – 没有内存泄漏
- IE9 – 内存泄漏(???)
- IE10 – 内存泄漏(???)
- IE11 – 没有内存泄漏
- 边缘(20) – 没有内存泄漏
- Chrome(50) – 无内存泄漏
- 火狐(46) – 很难说,泄漏不严重,所以也许只是低效的垃圾收集器? 完成一个额外的4MB没有明显的原因。
- 歌剧(36) – 没有内存泄漏
- Safari(9) – 没有内存泄漏
结论:出血边缘的应用程序可能会逃脱不去事件侦听器。 但是我仍然认为这是一个很好的做法,尽pipe烦恼。