If I have a parent element with children who have event listeners bound to them, do I need to remove those event listeners before I clear the parent? (i.e., parent.innerHTML = '';
) Could there be memory leaks if event listeners are not unbound from an element if it's removed from the DOM?
如果我有一个父元素,其中包含绑定了事件侦听器的子节点,那么在清除父节点之前是否需要删除这些事件侦听器? (即,parent.innerHTML ='';)如果事件侦听器从DOM中删除,如果从元素中取消它,是否会出现内存泄漏?
2 个解决方案
#1
26
Short answer: yes
简短回答:是的
Long answer: Most browsers handle this correctly and remove those handlers themselves. There are some older browsers (IE 6 and 7, if i recall correctly) that are messing this up. Yes, there could be memory leaks. You should not have to worry about this, but you need to. Have a look at this document.
答案很长:大多数浏览器都能正确处理并自行删除这些处理程序。有一些旧的浏览器(IE 6和7,如果我没记错的话)会弄乱这个。是的,可能存在内存泄漏。你不应该担心这个,但你需要。看看这个文件。
#2
22
Just to update the info here. I've been testing various browsers, specifically for memory leaks for circularly dependent event listeners on iframe onload events.
只是在这里更新信息。我一直在测试各种浏览器,特别是针对iframe onload事件上循环相关事件监听器的内存泄漏。
The code used (jsfiddle interferes with memory testing, so use your own server to test this):
使用的代码(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>
If there is no memory leak, the used memory will increase by around 1000kb or less after the tests are run. However, if there is a memory leak, the memory will increase by about 16,000kb. Removing the event listener first always results in lower memory usage (no leaks).
如果没有内存泄漏,运行测试后,使用的内存将增加大约1000kb或更少。但是,如果存在内存泄漏,内存将增加大约16,000kb。首先删除事件侦听器总是会导致内存使用率降低(无泄漏)。
Results:
结果:
- IE6 - memory leak
- IE6 - 内存泄漏
- IE7 - memory leak
- IE7 - 内存泄漏
- IE8 - no memory leak
- IE8 - 没有内存泄漏
- IE9 - memory leak (???)
- IE9 - 内存泄漏(???)
- IE10 - memory leak (???)
- IE10 - 内存泄漏(???)
- IE11 - no memory leak
- IE11 - 没有内存泄漏
- Edge (20) - no memory leak
- 边缘(20) - 没有内存泄漏
- Chrome (50) - no memory leak
- Chrome(50) - 没有内存泄漏
- Firefox (46) - hard to say, doesn't leak badly, so maybe just inefficient garbage collector? Finishes with an extra 4MB for no apparent reason.
- Firefox(46) - 很难说,不会泄漏严重,所以也许只是低效的垃圾收集器?没有明显原因,额外增加4MB。
- Opera (36) - no memory leak
- Opera(36) - 没有内存泄漏
- Safari (9) - no memory leak
- Safari(9) - 没有内存泄漏
Conclusion: Bleeding edge applications can probably get away with not removing event listeners. But I'd still consider it good practice, in spite of the annoyance.
结论:出血边缘应用程序可能无法移除事件侦听器。但是,尽管烦恼,我还是认为这是一种很好的做法。
#1
26
Short answer: yes
简短回答:是的
Long answer: Most browsers handle this correctly and remove those handlers themselves. There are some older browsers (IE 6 and 7, if i recall correctly) that are messing this up. Yes, there could be memory leaks. You should not have to worry about this, but you need to. Have a look at this document.
答案很长:大多数浏览器都能正确处理并自行删除这些处理程序。有一些旧的浏览器(IE 6和7,如果我没记错的话)会弄乱这个。是的,可能存在内存泄漏。你不应该担心这个,但你需要。看看这个文件。
#2
22
Just to update the info here. I've been testing various browsers, specifically for memory leaks for circularly dependent event listeners on iframe onload events.
只是在这里更新信息。我一直在测试各种浏览器,特别是针对iframe onload事件上循环相关事件监听器的内存泄漏。
The code used (jsfiddle interferes with memory testing, so use your own server to test this):
使用的代码(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>
If there is no memory leak, the used memory will increase by around 1000kb or less after the tests are run. However, if there is a memory leak, the memory will increase by about 16,000kb. Removing the event listener first always results in lower memory usage (no leaks).
如果没有内存泄漏,运行测试后,使用的内存将增加大约1000kb或更少。但是,如果存在内存泄漏,内存将增加大约16,000kb。首先删除事件侦听器总是会导致内存使用率降低(无泄漏)。
Results:
结果:
- IE6 - memory leak
- IE6 - 内存泄漏
- IE7 - memory leak
- IE7 - 内存泄漏
- IE8 - no memory leak
- IE8 - 没有内存泄漏
- IE9 - memory leak (???)
- IE9 - 内存泄漏(???)
- IE10 - memory leak (???)
- IE10 - 内存泄漏(???)
- IE11 - no memory leak
- IE11 - 没有内存泄漏
- Edge (20) - no memory leak
- 边缘(20) - 没有内存泄漏
- Chrome (50) - no memory leak
- Chrome(50) - 没有内存泄漏
- Firefox (46) - hard to say, doesn't leak badly, so maybe just inefficient garbage collector? Finishes with an extra 4MB for no apparent reason.
- Firefox(46) - 很难说,不会泄漏严重,所以也许只是低效的垃圾收集器?没有明显原因,额外增加4MB。
- Opera (36) - no memory leak
- Opera(36) - 没有内存泄漏
- Safari (9) - no memory leak
- Safari(9) - 没有内存泄漏
Conclusion: Bleeding edge applications can probably get away with not removing event listeners. But I'd still consider it good practice, in spite of the annoyance.
结论:出血边缘应用程序可能无法移除事件侦听器。但是,尽管烦恼,我还是认为这是一种很好的做法。