Is there a way to count the amount of times that the DOM has been appended to?
If you're stricly after .append(), you can just patch it, like:
var _origAppend = $.fn.append;
$.appendCount = 0;
$.fn.append = function() {
$.appendCount++;
return _origAppend.apply(this, arguments);
};
Now, you could just access $.appendCount at anytime to see how often it was called. However, be aware that there are lots of functions which can manipulate the DOM. It might be a more clever idea, to patch jQuery.fn.domManip instead. That method is called internally basically at any dom manipulation (like you might have suspected because of the name)
You can use the mutation events.
Be aware they have a huge performance impact!
The mutation event module is designed to allow notification of any changes to the structure of a document, including attr and text modifications. It may be noted that none of the mutation events listed are designated as cancelable. This stems from the fact that it is very difficult to make use of existing DOM interfaces which cause document modifications if any change to the document might or might not take place due to cancelation of the related event. Although this is still a desired capability, it was decided that it would be better left until the addition of transactions into the DOM.
Spec
Related
I need to create a simple tooltip library that works like this:
every DOM element with a specific attribute combination (like class="tooltip", data-tooltip-text="some text") automatically displays a tooltip (containing text from data attr) on hover.
This behavior must persist through external DOM manipulation. I really like the idea of utilizing a HTMLcollection for this, for its "live" nature, as iterating the whole DOM with every DOM change sounds potentially very demanding.
Now I would love to watch/listen the collection and run a sequence every time it changes (iterate through the nodes, see if they have a listener, add it if they don't).
How do I do this? The watch and observe methods seem to (if I understand correctly) be capable of that, but they are now deprecated. MDN says that Proxy covers most use cases, but does it cover mine (I haven't found a way to make it work)? Or is there some other way I'm missing?
And what about MutationObserver? I assume that deep-observing the whole application and repeatedly fetching a new NodeList via querySelectorAll with every single change would be too demanding (the library should run over a React application). Dynamically committing the HTMLCollection (as a value) into DOM via React and then (shallowly) listening for changes with MutationObserver might work, but I doubt that would be a good idea either.
This has been on my mind for a few days now.
As per the docs, React has synthetic event system, which is a a cross-browser wrapper around the browser's native event. Going through the docs, is my understanding correct that the custom (synthetic) event system, isn't about efficiency but rather cross-browser compatibility.
In other words, React still appends the event to the element rather than the more efficient approach of event-delegation on the parent element?
I also noticed this in Firefox Inspector which raised the initial curiosity.
The reason for asking the question is that I am working on an app where a user maybe able to select a thousand elements & drag them around the screen, so eventually event delegation is going to come up.
Alright, you perhaps already figured everything on your own, but as I asked myself the same questions, I figured I'd leave this here in case someone else is curious about not only using React but also getting an idea about how it works.
So, I'm not entirely sure about your question (especially the "append the event to element" part) but:
React is all about the virtual DOM. As the name implies, it is therefore built on top of the "real" environment that is the DOM. Consequently, everything takes place in that abstracted layer, including event handling.
Events appear in their "natural" environment, so the DOM or native (depending on the flavor of react you are using)
Consequently, you first need to bring the events up to the virtual DOM, compute your changes there and dispatch them to the representation of components in the virtual DOM, then bring the relevant changes back down to be reflected in the DOM appropriately.
Carrying changes up to the virtual DOM is effectively done by top-level delegation. This means that React itself listens to all events at a document level. This also means that technically, all your events go through one capture + bubbling loop before even entering the React-specific code. I would not be able to say what that implies performance wise, because you do "lose" the time associated to that first DOM traversal, but on the other hand you will do all your changes in the virtual DOM, which is faster than doing them in the real DOM...
Finally, SyntheticEvent is indeed a wrapper, which aims at reducing cross-browser compatibility issues. It also introduces pooling, which makes the thing faster by reducing garbage collection time. Besides, as one native event can generate several SyntheticEvent, it technically lets you create new ones easily (like a syntheticTap event that could be emitted if you receive a native touchStart then a native touchEnd in succession).
I have written a post with more details here. It is far from perfect and their might be some imprecision, but it can perhaps give you some more info on the topic.
I am newbie to jQuery. I am bit confused whether is it fine or may cause memory leak ?
Here is the code: This method is called on certain date filters for each new values
function preapreTooltip(chart) {
var tickLength = chart.xAxis[0].tickPositions.length,
ticks = chart.xAxis[0].ticks,
tickPositions = chart.xAxis[0].tickPositions;
for ( var iCntr = 0; iCntr < tickLength; iCntr++) {
var tickVal = tickPositions[iCntr];
//.label or .mark or both
(function(tickVal) { // Is this good practice to call function like this?
ticks[tickVal].label
.on('mouseover', function(event) { // Is this good practice to call function like this?
var label = '', labelCnt=0;
$(chart.series).each(function(nCntr, series) {
//business logic for each series
});
// calling method to show values in a popup
});
ticks[tickVal].label.on('mouseout', function(event) { // Is this good practice to call function like this?
try {
hideWrapper(); // hides popup
} catch (e) {
// do nothing
}
});
})(tickVal);
}
}
Whilst there are browser specific issues that need to be avoided when writing large pure JavaScript projects, when using a library such as jQuery it should be assumed that the library's design helps you avoid these problems. However, considering memory leaks are rather hard to track down, and each different version of a particular browser could behave differently - it is far better to know how to generally avoid memory leaks than being specific:
If your code is being iterated many times, make sure the variables you are using can be discarded by garbage collection, and are not tied up in closure references.
If your code is dealing with large data structures, make sure you have a way of removing or nullifying the data.
If your code constructs many objects, functions and event listeners - it is always best to include some deconstructive code too.
Try to avoid attaching javascript objects or functions to elements directly as an attribute - i.e. element.onclick = function(){}.
If in doubt, always tidy up when your code is finished.
You seem to believe that it is the way of calling a function that will have an effect on leaking, however it is always much more likely to be the content of those functions that could cause a problem.
With your code above, my only suggestions would be:
Whenever using event listeners try and find a way to reuse functions rather than creating one per element. This can be achieved by using event delegation (trapping the event on an ancestor/parent and delegating the reaction to the event.target), or coding a singular general function to deal with your elements in a relative way, most often relative to this or $(this).
When needing to create many event handlers, it is usually best to store those event listeners as named functions so you can remove them again when you are finished. This would mean avoiding using anonymous functions as you are doing. However, if you know that it is only your code dealing with the DOM, you can fallback to using $(elements).unbind('click') to remove all click handlers (anonymous or not) applied using jQuery to the selected elements. If you do use this latter method however, it is definitely better to use jQuery's event namespacing ability - so that you know you are only removing your events. i.e. $(elements).unbind('click.my_app');. This obviously means you do have to bind the events using $(elements).bind('click.my_app', function(){...});
being more specific:
auto calling an anonymous function
(function(){
/*
running an anonymous function this way will never cause a memory
leak because memory leaks (at least the ones we have control over)
require a variable reference getting caught in memory with the
JavaScript runtime still believing that the variable is in use,
when it isn't - meaning that it never gets garbage collected.
This construction has nothing to reference it, and so will be
forgotten the second it has been evaluated.
*/
})();
adding an anonymous event listener with jQuery:
var really_large_variable = {/*Imagine lots of data here*/};
$(element).click(function(){
/*
Whilst I will admit not having investigated to see how jQuery
handles its event listeners onunload, I doubt if it is auto-
matically unbinding them. This is because for most code they
wont cause a problem, especially if only a few are in use. For
larger projects though it is a good idea to create some beforeunload
or unload handlers that delete data and unbind any event handling.
The reason for this is not to protect against the reference of the
function itself, but to make sure the references the function keeps
alive are removed. This is all down to how JS scope works, if you
have never read up on JavaScript scope... I suggest you do so.
As an example however, this anonymous function has access to the
`really_large_variable` above - and will prevent any garbage collection
system from deleting the data contained in `really_large_variable`
even if this function or any other code never makes use of it.
When the page unloads you would hope that the browser would be able
to know to clear the memory involved, but you can't be 100% certain
it will *(especially the likes of IE6/7)* - so it is always best
to either make sure you set the contents of `really_large_variable` to null
or make sure you remove your references to your closures/event listeners.
*/
});
tearDowns and deconstruction
I've focused - with regard to my explanations - on when the page is no longer required and the user is navigating away. However the above becomes even more relevant in today's world of ajaxed content and highly dynamic interfaces; GUIs that are constantly creating and trashing elements.
If you are creating a dynamic javascript app, I cannot stress how important it is to have constructors with .tearDown or .deconstruct methods that are executed when the code is no longer required. These should step through large custom object constructs and nullify their content, as well as removing event listeners and elements that have been dynamically created and are no longer of use. You should also use jQuery's empty method before replacing an element's content - this can be better explained in their words:
http://api.jquery.com/empty/
To avoid memory leaks, jQuery removes other constructs such as data and event handlers from the child elements before removing the elements themselves.
If you want to remove elements without destroying their data or event handlers (so they can be re-added later), use .detach() instead.
Not only does coding with tearDown methods force you to do so more tidily (i.e. making sure you to keep related code, events and elements namespaced together), it generally means you build code in a more modular fashion; which is obviously far better for future-proofing your app, for read-ability, and for anyone else who may take over your project at a later date.
Here is an excellent article to detect memory leak using Chrome or Safari : http://javascript.crockford.com/memory/leak.html
It is use not well known functionalities of Developer Tools panel.
Interesting and very useful!
EDIT
It was not the good link (but still useful). Here is the one : http://gent.ilcore.com/2011/08/finding-memory-leaks.html
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.
In the last couple of years I've been using JavaScript name spaces espoused by YUI as my default way of formatting JavaScript code.
All in all it works well in more complex environments where many web widgets may be stuck together at different times.
Until recently I've almost always used added event handlers in the HTML by calling the handlers from the name spaced object itself.
I've been using JQuery lately and have been setting the handlers inside of the ready function rather than in the HTML.
As I do more and more of that it seems that the closure of the JQuery ready function is taking the place of the name space object.
What I am ending up with now (at least for one widget/tool type pages) is a name space object that primarily deals holds data and a bunch of closed event handlers that I access the name space object for data specific purposes.
My question is, what are some best practices for dealing with closures verses a Name space object particularly as it relates to event handlers?
Or, similarly, what are some best practices for setting up event handlers, should they be "heavy weight" and handle the processing themselves, or hand off to more library like code.
Personally it's harder to keep track of the flow of many separate "heavy weight" event handlers.
This is a very subjective question. That being said, I'll do my best to give what I think are the pros/cons of each approach.
Namespace Objects:
yourNamespace.events.someClickHandler = function(event) {...}
$(function() {
$("#someElement").click(yourNamespace.events.someClickHandler);
}
One of the first "cons" of this approach is the separation of your event handler from it's hookup. You can avoid this by hooking up each event after it is defined (as I did in the example above), but then you wind up with a whole lot of "$(function() {" lines throughout your code.
Another "con" of this style is the long names for your event handlers (eg. "yourNamespace.events.someClickHandler"). You can use aliases:
var events = yourNamespace.events;
$("#someElement").click(events.someClickHandler);
and shorter namespace names to mitigate this somewhat, but there's really no way to get around it.
So with all those cons, why would anyone use the namespace pattern? Well, one "pro" of it is that the events are accessible. Let's say (for debugging purposes) you want to log the event object that gets passed to your click handler. Using Firebug you could do something like:
var oldHandler = yourNamespace.events.someClickHandler;
var newHandler = function(e) {console.log(e); oldHandler(e);}
$("#someElement").unbind("click");
$("#someElement").click(yourNamespace.events.someClickHandler);
and, without even refreshing the page, you could get your event logged.
Similarly, this style has another pro of re-usability. If you want to make a new click handler that is similar to the old one, but also does x, y, and z, you could do:
yourNamespace.events.advancedClickHandler = function(event) {
yourNamespace.events.someClickHandler(e);
x(); y(); z();
}
Now in contrast we have the "closure" style (I'd prefer to call it the "anonymous function" style).
$(function() {
$("#someElement").click(function(event) {...});
}
It's clearly more concise, the handler's definition is about as close as it can get to the hook-up, and I think it even uses a teeny bit less memory because there's no variable reference. BUT, you won't be able to do any live debugging stuff, you won't be able to hook that handler up anywhere else, or extend it in some new handler, or anything like that, because your handler only exists for the moment when you hook it up.
So, hopefully that helps. In my experience the namespace object style is generally the preferred method, especially the more hardcore/serious the JS project is. But it definitely has some disadvantages; there really is no perfect (ie. perfectly clean/ and re-usable) way of hooking up events in JS at this time.