【发布时间】:2011-08-27 09:21:35
【问题描述】:
如果我的父元素的子元素绑定了事件侦听器,我是否需要在清除父元素之前删除这些事件侦听器? (即parent.innerHTML = '';)如果事件侦听器未从元素中解除绑定(如果从 DOM 中移除),是否会出现内存泄漏?
【问题讨论】:
标签: javascript dom memory-leaks dom-events
如果我的父元素的子元素绑定了事件侦听器,我是否需要在清除父元素之前删除这些事件侦听器? (即parent.innerHTML = '';)如果事件侦听器未从元素中解除绑定(如果从 DOM 中移除),是否会出现内存泄漏?
【问题讨论】:
标签: javascript dom memory-leaks dom-events
只是在这里更新信息。我一直在测试各种浏览器,特别是针对 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,000kb。首先删除事件侦听器总是会降低内存使用率(无泄漏)。
结果:
结论: 不删除事件侦听器可能会导致出血边缘的应用程序侥幸逃脱。但我仍然认为这是一种很好的做法,尽管很烦人。
【讨论】:
简短回答:是
长答案:大多数浏览器都会正确处理此问题并自行删除这些处理程序。有一些旧的浏览器(IE 6 和 7,如果我没记错的话)搞砸了。是的,可能存在内存泄漏。你不应该担心这个,但你需要。看看this document。
【讨论】:
IE < 10 可以安全地被认为已弃用,并且此时任何访问雅虎和 AOL 以外的网站的人都不会使用它。无论如何,在这一点上反常使用 IE 的任何人都更有可能成为印度电话诈骗或感染病毒的受害者,而不是事件处理程序减慢浏览器速度的问题。