If I make ajax requests that remove the body HTML and append new HTML, do I need to also remove any event handlers that were added to the previous HTML?
I noticed that if I don't, everything works fine. Does the browser free the memory and stuff? What if I do thousands of such ajax requests without refreshing the browser? Will I get memory leaks?
If you add jQuery event handlers :
they will be cleaned if you use jQuery removing/replacing functions
they won't be cleaned if you use direct DOM functions
On most function documentations, you have a comment similar to this one :
When .html() is used to set an element's content, any content that was
in that element is completely replaced by the new content.
Additionally, jQuery removes other constructs such as data and event
handlers from child elements before replacing those elements with the
new content.
If you're coherent, you'll have no memory leak, you don't have to manually remove data or event handlers. There's usually no problem in having a page kept open for days and issuing thousands of Ajax requests and changing the screen accordingly.
Related
I'm working with a large template of charts and other widgets. I also manually implemented some ajax tabs. Now whenever those tabs load new content (charts), the problem is that all the template scripts in the head tag won't work with those ajax-loaded elements anymore.
I know, normally you would use .live for this kind of problem, but this would mean to go into the whole 50k lines-js template and change everything to .live calls... Not really able to do that.
Is there instead a jquery way of reloading/reactivating all the scripts within the head-tag?
First off .live() has long since been deprecated and even removed from the latest versions of jQuery. You should never be thinking of using .live().
Second, as it sounds like you already know, the "right" way to fix this is to change your code to use the delegated form of .on() which is what replaced .live(). Yes, change all the code that does it the wrong way. Here's a post on using the delegated form of .on() instead of .live().
Third, a work-around would be to put all your initialization code that hooks up these event handlers into a single function (or called by a single function). Then, you call that single function upon initialization and then you can call that single function any time later after you reload your content. The trick is that you can only put code into that initialization function that can be called or should be called more than once after you content has been reloaded. If you put some event handlers in there that should not be in there, then you may get duplicate event handlers installed. So, only event handler initialization that applies to the replaced content should go in this function.
Suppose that function was called initDynamicContent, then it could look like this:
// init event handlers on the original version of the dynamic content
$(document).ready(initDynamicContent);
Then, sometime later after you replace the dynamic content, you can just do:
// code here that replaces the dynamic content with new content
initDynamicContent();
There is no magic jQuery way for this to happen automatically. jQuery has absolutely no way of knowing which code should be run again and which code should not.
I'm trying to get rid of memory leak in IE8, caused by reference loops between event handlers and DOM elements during iframe navigation. I can not modify other scripts on the page.
So the idea was to walk through the DOM and window object and nullify all fields to ensure no DOM element references event handler.
Now the problem is I need to do it after all other unload handlers are run, because other handlers might depend on fields I'm going to nullify.
I tried to do store document object before navigation somewhere in parent window, and then, after navigation in my iframe completes (onload event), run cleanup on stored document object. However, apparently, you can't do it, because after old page is unloaded accessing this document becomes illegal (access error).
The other approach I tried was to find way to add window unload handler, which will be guaranteed to be called the last, however, I did not successed in it so far. To achieve that I tried to call all handlers for the unload event, clean them, and than run my code, but I did not found a way to trigger unload event manually.
Any ideas? Unfortunately, page uses jQuery and Microsoft Ajax, which have their own unload handlers. In particular, my nullification breaks MS Ajax unload handler, because it removes all library namespaces.
I think it's impossible to guarantee the removal of all event listeners if you don't know how they were attached in the first place.
IE 8 uses attachEvent, so if a listener is added like:
element.attachEvent('onclick', function(){...});
then you have no way of knowing that the listener is attached. Setting the onclick property to some new value (say '') will not remove the listener, nor will adding another by attachEvent. In DOM compliant browsers, replacing an element with a clone of itself will remove listeners, but not in IE where attachEVent has been used.
Strategies for avoiding memory leaks usually involve not creating circular references involving DOM elements.
Strategies for removing all listeners generally rely on keeping a list of what's been added, then explicitly removing them before the page unloads.
Both can be difficult and are impossible to guarantee if you don't have control of all code in the page.
Is there anyway to listen for elements adding themselves to the DOM after load? Currently I have a bunch of tables using DataTables and I have a bunch of other elements that I would like to manipulate when and if the type of element I am looking for is found to have "appeared" on the page. Seeing as what I am attempting to do only works on elements currently on the page when loaded but not after they load such is the case with many elements currently in play.
Ultimately I am currently looking for a means of avoiding going back through the entire code base just to make something happen only if something is found on the page, but after its loaded.
There's no "element added to dom" sort of event that's cross-browser compatible, and the ones that exist for specific browsers are generally discouraged as they tend to cause more issues than they solve.
Usually the issue with elements not existing in the DOM is that they miss event-binding. jQuery has awesome event-delegation that can be used to bind events to a container so that when an event bubbles up to the container, the callback is fired in the context of the element that received the event.
For example, you could bind events using:
$('a').click(doStuff);
but that would not work for any new links, instead you could use something like:
$('#some-container').on('click', 'a', doStuff);
which would intercept all click events on all links in the #some-container element, regardless of when they were added to the page.
I'm working on a completely ajax web project where a section content is always generated through DOM manipulation or using jQuery's load function. I had been using "live" but am very interested in moving away from "live" and using "on" for performance benefits. When a new page loads a whole new set of bindings required for that section also need to get loaded. The html sections have some parent DOMs (basically wrappers for different content areas of the web page) that never change allowing me to do bindings on them for all future DOM elements that will be created on the page.
In terms of memory and performance trade off which is generally the better way to handle event bindings?
After a new section has finished loading its html, bind all the events needed for that specific page instance on DOM elements that will be removed when a page changes.
Bind every event on the very first page load to DOM elements (not to the document though like live does) that are known to always exist.
Memory issues with listeners can usually be dealt with fairly easily (don't hold large chunks of data in closures, don't create circular references, use delegation, etc.).
"Live" just uses delegation (as far as I know) - you can implement delegation quite simply without it using simple criteria, e.g. class or id, with listeners on the unchanging parent elements. Delegation is a good strategy where it replaces numerous other listeners, the content is constantly being changed and identifying elements that should call functions is simple.
If you follow a strategy of attaching numerous new listeners every time content changes, you also have to detach the old ones when they are replaced as a strategy to reduce the likelihood of memory leaks. Performance (in terms of time taken to attach and remove listeners as part of the DOM update) usually isn't that much of an issue unless you are doing hundreds of them.
With delegation, a parent element listens for events, checks if the event.target/srcElement is one it cares about for that event, then calls the appropriate function perhaps using call to set the value of this if required.
Note that you can also simply include inline listeners in the inserted HTML, then you never need to worry about memory leaks, delegation or adding and removing listeners. Inline listeners using a simple function call are no more complex than adding any other attribute (class, id, whatever) and require zero extra programming on the client. I don't think inline listeners were ever an issue for memory leaks.
Of course the "unobtrusive javascript" mob will howl, but they are very practical, functional and robust, not to mention supported by every browser that ever supported javascript.
If I attached a bunch of events to some DOM elements - and then remove them - will the memory used for their event handlers or other attributes still be used?
I ask because I want to know if I will use a bunch of memory if I keep refilling an area of a page with new elements from AJAX requests and binding events to them - only to delete them and repeat the process when a new AJAX result comes in.
Yes, modern browsers (eventually) release the memory used by event handlers in DOM nodes. However, old versions of Internet Explorer don't, so it's always good practice to remove event listeners before removing the nodes from the DOM.
This is a good article for understanding what's going on: http://msdn.microsoft.com/en-us/library/bb250448(v=vs.85).aspx