18

Given the following code

<div id="app">
  <div id="foo" />
</div>

<script>
  $('#foo').bind('click', function(){});
</script>

I plan on replacing the contents of #app [e.g. $('#app').html('...');, or innerHTML = '...';]. I know that I can use jQuery's .remove() which calls a 'destroy' handler that unbinds events. The fact that there is a destroy handler set up to remove events leads me to believe that without unbinding the events, when the DOM element is removed, the handler will still exist in memory.

So, if the DOM element #foo no longer exists, does the handler disappear as well, or does it get lost in browser memory?

Kappers
  • 1,341
  • 3
  • 15
  • 26
  • I'd like to know as well. Not too sure, but I'd like to think that java would clean itself after some time if it finds an object no longer being used. – robx May 03 '11 at 21:04
  • 2
    @robx: JavaScript, not Java. And yes, JavaScript is a garbage-collected language, but the DOM part of a browser may not be (almost certainly isn't) written in JavaScript. – T.J. Crowder May 03 '11 at 21:05
  • Woop, something i've pondered myself unsure of ;) – robx May 03 '11 at 21:09
  • possible duplicate of [Do events handlers on a DOM node get deleted with the node?](http://stackoverflow.com/questions/4337582/do-events-handlers-on-a-dom-node-get-deleted-with-the-node) – T.J. Crowder May 03 '11 at 21:12

2 Answers2

15

jQuery keeps track of event handlers itself, which is part of why you need to use unbind (nowadays it's off) if you're removing the element from the DOM not through a jQuery method (if you use jQuery's empty or remove, as you mentioned it handles this itself inernally). This is so jQuery knows it can release its reference to the handler.

If it weren't for that, then in theory, you wouldn't have to do anything because once the DOM element is removed from memory, it's no longer reachable, and so in theory shouldn't keep the event handler in memory. That's the theory. The reality is very different, it can be very easy to end up with a situation (particularly on IE) where neither the DOM element nor the event handler can get cleaned up because they're each causing the other to stick around — a memory leak. JavaScript has no issue with circular references (it understands them and can release two things that are pointing to each other as long as nothing else is pointing to them), but the DOM part of the browser is likely to be written in a different language with a different garbage collection mechanism (IE uses COM, which uses reference counting rather than reachability). jQuery helps you avoid this pitfall with IE (part of why it keeps track of event handlers), but you have to use unbind (nowadays off) (or remove elements via empty, remove, etc.) as a consequence.

The take away message: As you hook, so shall you unhook. :-) (And/or use jQuery when removing elements, since it will handle this.)

Somewhat related: If you're adding and removing elements a lot, you might look to see if event delegation (which jQuery makes really easy via the delegation signatures for on) might help.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    I thought so. I'm using Backbone.js for an app, and didn't see anything in source, or documentation about unbinding events that are set up in Backbone.View. Many online examples of Backbone that I've seen aren't unbinding any events either (calling 'new View()' that overwrites content in an element but doesn't do any unbinding of the element's previous children). Wanted to make sure I account for these memory leaks if they will present themselves. – Kappers May 03 '11 at 21:16
5

Just happened to read the docs on jQuery's empty() method:

To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves.

Kappers
  • 1,341
  • 3
  • 15
  • 26