Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do Javascript event listeners need to be removed prior to removing the element they're attached to?

Suppose I have attached a variety of event listeners to various form elements. Later, I want to remove the entire form.

Is it necessary (or suggested) to unregister any event handlers that exist on the form and its elements? If so, what is the easiest way to remove all listeners on a collection of elements? What are the repercussions of not doing so? I'm using Prototype, if it matters.

Here's what I'm actually doing. I have a simple form, like this:

<form id="form">
  <input type="text" id="foo"/>
  <input type="text" id="bar"/>
</form>

I observe various events on the inputs, e.g.:

$('foo').observe('keypress', onFooKeypress);
$('bar').observe('keypress', onBarKeypress);

etc.

The form is submitted via AJAX and the response is a new copy of the form. I replace the old form with a copy of the new one doing something like $('form').replace(newForm). Am I accumulating a bunch of event cruft?

like image 443
Jeremy Kauffman Avatar asked Jul 16 '09 15:07

Jeremy Kauffman


2 Answers

Events which are not unregistered may not free their memory automatically. This is especially a problem in older versions of IE.

Prototype used to have an automatic garbage collection system for this, but the method has been removed in version 1.6. It is documented here. Whether the removal of the method means that the garbage collection no longer takes place, or the method just isn't publicly available anymore, I don't know. Also note that it was only ever called on page unload, meaning that if your users stay on the same page for a long time while doing a lot of AJAX and DOM updates, memory may leak to an unacceptable extent even during that one page visit.

like image 102
Jonas Høgh Avatar answered Nov 06 '22 22:11

Jonas Høgh


Yeah, a bit. Not enough to be a huge problem, but older versions of IE will leak under those circumstances.

As of Prototype 1.6.1 (currently in its final release candidate), the library handles this cleanup on page unload. When you use Prototype to add an event observer, it keeps a reference to that element in an array; on page unload, it loops through that array and removes all your observers.

However, if the user is going to stay on this page for a while, memory usage will accumulate over the life of the page. You have several options:

  1. Listen for events on an ancestor of the form, one that never gets replaced. Then, in your handler, check where the event came from. (i.e., "event delegation")

  2. Explicitly un-register all your calls before calling Element#replace. In your example, you'd do:

    $('foo', 'bar').each(Element.stopObserving);
    

This is equivalent to calling stopObserving with no arguments, which has the effect of removing all handlers on a given element.

I would recommend option 1.

(We've talked about doing automatic listener removal in a future version of Prototype as part of Element#update and Element#replace, but it's a performance trade-off.)

like image 22
savetheclocktower Avatar answered Nov 06 '22 22:11

savetheclocktower