I've inherited a jQuery application that does its work by calling AJAX services without leaving the page.
There is a list of items, where when you click on an item the detail of the item is displayed, events attached to the buttons, then the html is disposed and new html will be created, new events attached and so on and so forth.
I was wondering whether JavaScript garbage collection will automatically clean up those events, or do they go in some Map like data structure and create a memory leak. Am I supposed to clean them up explicitly?
If you always bind the same events, you could also use something like jQuery live() or the likes instead of always binding/unbinding them.
Javascript garbage collection will not remove bound events to removed elements. jQuery functions often do depending on what method you use.
In example, .html() or .remove() will remove events and not leak memory. When in doubt you can always use .empty().
In my opinion the .live() discussion is fairly beside the point of memory leaks. The usage of .live() should be done when it makes sense from an architecture standpoint. Unless you need the event to be bound before the element is added to the DOM, or exist after the element is removed (because it may be added again) then .bind() is really the proper and faster method to use. .live() is slower than .bind() because each event must fire at the element, bubble to the document and then bubble back up to the element in order to be processed by .live(), while with .bind it can execute right away.
Also, FYI both .bind() and .live() are deprecated in the newest version of jQuery (1.7). They will still function, but the new syntax is .on(), using delegation to replace .live(). This is because too much .live() really slows down pages because each .live binds another event to the document which must be listened and processed every single event.
if you want to make it easier on the GC and not make him search if it has references , so you should unbind / die all events to the div.
Related
I have a div with class="backdrop". This will be added to DOM when I click a button. To this is bound an event of 'wheel'.
I cannot avoid the binding of the event(happening through library) So i will want to unbind this globally.
I tried : $(".modal-backdrop.am-fade").unbind('wheel');
This works but I have to write this statement after each time the div is added to the DOM. I want something which I can write only once and would apply to all the divs which would be added to the DOM in future
I want something which I can write only once and would apply to all the divs which would be added to the DOM in future
If code in the library you're using is adding elements and binding events to them, you'll have to unbind them as you go, there's no alternative.
If you already have some way of triggering that (the library tells you when it adds a div), then you'll just have to have that code respond to that event.
If you don't already have some way of triggering it, you can use mutation observers to watch for the divs being added so you can unbind them. They're well-supported by modern browsers. Slightly less modern browsers may have sufficient support for the old mutation events that you can use a library that provides a mutation observer polyfill using mutation events (just search for "mutation observer polyfill"). Worst case, on really old browsers, you'll have to poll.
Of course, the best answer is to either stop using the library if it doesn't do what you want, or modify it (this is JavaScript, after all) so it doesn't do what you don't want.
I am registering a click listener on a DOM element via jQuery.on(). If later on that element is removed from the DOM -- maybe indirectly, e.g. by by replacing some parent's content via $(parent).html(...), should I still bother to remove my handler via jQuery.off()?
Even if the element will no longer trigger any event, I am worried about potential memory leaks. Does either jQuery or the browser take care of that and discard all registered handlers once an element is removed from the DOM?
Even if the element will no longer trigger any event, I am worried about potential memory leaks.
This is very good concern. To answer your question, take a look at $.fn.html implementation. From there you will learn that html will try to clean up stored event data:
// Remove element nodes and prevent memory leaks
if (elem.nodeType === 1) {
jQuery.cleanData(getAll(elem, false));
elem.innerHTML = value;
}
So in this case manually calling .off() is not necessary. However..
You need to remember that you should never ever try to remove elements with native methods like removeChild or setting innerHTML, since in this case there will be a memory leak for sure (if some data is stored, events are registered by jQuery, etc.). In this case it's more reliable to actually deregister event handlers with .off method. Or better use event propagation and instead or html('') use $.fn.remove.
It's better to call jQuery.off before removing your node, especially if it's a one page application which can contains a lot of events registered.
I have lot of jquery scripts which dont handle elements loaded or created on the fly, of course I can convert all my scrits and add the them the .live() function. However was wondering if there is any option or trick that could automatically simulate the live function in all the scripts without modifying them one by one manually.
Thanks for the comments , live is depreciated, so I restate my question with the .on() function.
There is not one trick that will make all existing event handler code work with dynamically loaded elements without updating each event handler unless you want to replace some jQuery methods with methods that work differently than jQuery has documented (not recommended). You would have to replace all jQuery event handling methods that you are currently using with methods that forced delegated event handling into them. This would be a bad way to do this. Not only would you be hacking jQuery into something that would be different than it is documented and opening yourself up to compatibility issues with other code, but you'd be forced into the most inefficient use of delegated event handling (which is why .live() was removed in the first place). Do not do this. Fix your code to use the proper method of delegated event handling. It's not hard at all.
.live() has been deprecated and even removed from the latest versions of jQuery. You should not use it. There is a form of .on() that will allow you to use delegated event handling for dynamically loaded objects. You can see how to use the proper form of .on() for dynamically loaded elements in this post: jQuery .live() vs .on() method for adding a click event after loading dynamic html.
The "proper" way to use .on() for dynamic elements is like this:
$('#parent').on("click", "#child", function() {});
where you select the closest parent to the dynamic element that is not itself dynamically loaded and bind the event handler to that element.
.live() was removed because it put all delegated event handlers on the document object somewhat analogous to this:
$(document).on("click", "#child", function() {});
If, however, you used a number of delegated event handlers like this, performance could start to bog down. That's because when you do it this way and you click anywhere in the document and that click bubbles up to the document, it has to compare every single selector in every single .live() event handler you had to the current clicked object. Since selector comparisons are not always fast, this could really bog down the processing of events.
When you place the event handler on an object closer to the actual object, you end up with far event handlers there and thus far fewer selectors to compare to and processing of the events works faster.
Here's a reference on some differences between static event handlers and delegated event handlers and some useful notes on them: JQuery Event Handlers - What's the "Best" method
Is onclick in HTML identical to .click() in jQuery?
Obviously they are identical from a usability standpoint, but I am curious how the browser handles them.
jQuery attaches events using JavaScript behind the scenes.
An important difference is that jQuery allows multiple events to be bound using click(), where as you can only attach one handler using onclick. This is because jQuery uses either addEventListener or attachEvent behind the scenes, as opposed to binding to .onclick directly.
Furthermore, attaching handlers via JavaScript (using jQuery or not) promotes unobtrusive JavaScript (i.e. not mixing JavaScript and HTML), which is a good thing.
No it's not the same. OnClick sets a property of a DOM element, where .click() adds an eventListener.
The differnce between them is that every DOM element can only have on property of a type at once. So if you use onClick= twice on an element, only last added will win, the first will be overwritten.
This will always alert 2, cause the first attachment will be overwritten:
myDiv.onclick = function(){alert('1')}
myDiv.onclick = function(){alert('2')}
Using .click() or .addEventListener('click', myFunction), you can add as many functions as you want. So the following will alert 1 and 2:
myDiv.click(function(){alert('1')})
myDiv.click(function(){alert('2')})
The differnt between jquerys .click() and .addEventListener() is, that the jquery solution works in all browser, cause IE<=8 has a different syntax (attchEvent). And that you can unbind all click handlers in once. The normal JavaScript solution can only detach the passed function not all of them.
(Noting that jQuery is a JavaScript library and so can't do anything that you couldn't do in JavaScript yourself if you had the time...)
The jQuery .click() method is different to onclick in a few key ways. In no particular order:
jQuery endeavours to normalise the event object so that you don't have to worry about the (mostly) minor differences between browsers
jQuery binds events with .addEventListener() or .attachEvent() depending on what your browser supports, so, again, you don't have to worry about the difference
jQuery guarantees that where multiple handlers have been bound for the same element and event they will be run in the order they were attached (noting that using .onclick you can only bind one handler anyway, but with .addEventListener() and .attachEvent() you can bind multiple handlers)
if you use jQuery's .on() or .delegate() (or the deprecated .live()) to attach events, rather than shortcut methods like .click(), it is easy to setup event delegation
Behind the scenes all the standard browser events are still happening, but jQuery provides a wrapper for them to make all of the above happen. Of course there are some other differences, but I see the above as the most important.
Obviously they are identical from a usability standpoint
No they're not. It would be much more accurate to say that jQuery's events are (almost) the same as .addEventListener() or .attachEvent() in how you use them, but even then as detailed above jQuery gives you an extra level of abstraction to save you having to code it all yourself.
the .click() even in JQuery is not the same. It is a piece of codes on top of the onclick in html. JQuery allows to bind methods to a event using this layer on top of the normal html events.
You can change/override .click() to adapt your needs. For instance when using a mobile browser or pda etc.
I have a grid and there is a column which contains <a> anchor tag with some additional information in <data-..> tag and has a class name <class='myspeciallink'>. And in my unobtrusive JS script I select all the elements with that class name and apply live('click'). I need that to be live() because the grid gets generated in the runtime.
What happens inside the live('click') handler? I use that additional data and add a <div> to the page based on that data. Which in its turn used to generate jQuery UI dialog. It works great on my computer.
But! How could that work in real-world? Should I be bothered about possible performance implications? I feel that applying live() on more than a dozen elements instantaneously
would affect the performance. Especially with rather complicated handler like mine - it needs to get the data, parse the data, create a div, apply a dialog and etc.
Does that smell like a bad design? Could you suggest a different approach or my concerns are unfounded? Can I use some sort of a profiler tool to find the bottlenecks in my javascript?
UPD: Still nobody suggested any profiling tool. firebug and chrome dev tools are good, but maybe there is something even better?
live("click") is actually better up-front from a performance standpoint: Instead of binding an event handler to each matched element, you're applying a single event handler which waits for events to bubble up and then sees if the element that triggered the event matches the selector .live was called on.
Compare this to $('selector').click(...) which does loop over each element and bind a new event handler. live('click') has no additional overhead regardless of how many page elements match its selector. Depending on how many elements your selector matches, using .live can avoid a delay of up to a few seconds during the initial load of each page.
However, the event handler must check each event which bubbles up against its selector, to see if there is a match. This is going to add a small amount of overhead to every click event, but chances are very good that your users will not notice the difference.
Peter bailey also has a nice post about this: Performance difference between jQuery's .live('click', fn) and .click(fn)