Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do I need to remove event listeners before removing elements?

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?

like image 206
Uyghur Lives Matter Avatar asked May 17 '11 16:05

Uyghur Lives Matter


People also ask

Are event listeners removed when element is removed?

According to the jquery Documentation when using remove() method over an element, all event listeners are removed from memory. This affects the element it selft and all child nodes. If you want to keep the event listners in memory you should use . detach() instead.

Should you always remove event listeners?

The event listeners need to be removed due to following reason. Avoid memory leaks, if the browser is not handled it properly. Modern browsers will garbage collect event handlers of removed DOM elements but it is not true in cases of legacy browses like IE which will create memory leaks.

What happens if you don't remove event listeners?

The main reason you should remove event listeners before destroying the component which added them is because once your component is gone, the function that should be executed when the event happens is gone as well (in most cases) so, if the element you bound the listener to outlasts the component, when the event ...

How do you remove all event listeners from an element?

To remove all event listeners from an element: Use the cloneNode() method to clone the element. Replace the original element with the clone. The cloneNode() method copies the node's attributes and their values, but doesn't copy the event listeners.


1 Answers

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.

like image 147
Dwight Avatar answered Sep 21 '22 13:09

Dwight