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

发布于 2024-11-08 15:04:21 字数 133 浏览 0 评论 0原文

如果我有一个父元素,其子元素绑定了事件侦听器,那么在清除父元素之前是否需要删除这些事件侦听器? (即,parent.innerHTML = '';)如果从 DOM 中删除元素后事件侦听器未与该元素解除绑定,是否会出现内存泄漏?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

忆梦 2024-11-15 15:04:21

只是为了更新这里的信息。我一直在测试各种浏览器,特别是针对 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。首先删除事件侦听器总是会导致较低的内存使用量(无泄漏)。

结果:

  • IE6 - 内存泄漏
  • IE7 - 内存泄漏
  • IE8 - 无内存泄漏
  • IE9 - 内存泄漏 (???)
  • IE10 - 内存泄漏 (???)
  • IE11 - 无内存泄漏
  • Edge (20) - 无内存泄漏
  • Chrome (50) - 没有内存泄漏
  • Firefox (46) - 很难说,泄漏并不严重,所以也许只是低效的垃圾收集器?无缘无故地多了 4MB。
  • Opera (36) - 无内存泄漏
  • Safari (9) - 无内存泄漏

结论:
前沿应用程序可能可以通过不删除事件侦听器来逃脱惩罚。但尽管很烦人,我仍然认为这是一个很好的做法。

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.

The code used (jsfiddle interferes with memory testing, so use your own server to test this):

<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).

Results:

  • IE6 - memory leak
  • IE7 - memory leak
  • IE8 - no memory leak
  • IE9 - memory leak (???)
  • IE10 - memory leak (???)
  • IE11 - no memory leak
  • Edge (20) - no memory leak
  • Chrome (50) - no memory leak
  • Firefox (46) - hard to say, doesn't leak badly, so maybe just inefficient garbage collector? Finishes with an extra 4MB for no apparent reason.
  • Opera (36) - no memory leak
  • Safari (9) - no memory leak

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.

烙印 2024-11-15 15:04:21

简短回答:

详细回答:大多数浏览器都会正确处理此问题并自行删除这些处理程序。有一些较旧的浏览器(IE 6 和 7,如果我没记错的话)会搞乱这个。是的,可能存在内存泄漏。您不必担心这一点,但您需要担心。请查看此文档

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文