Why is it faster to access the DOM through a cached variable? - javascript

I am trying to improve my knowledge of javascript and while searching for some "best practices", someone pointed out to me that it is faster to cache the DOM document and then access it through that var instead of accessing the document object directly.
You can see the results here, on an edit I made on jsperf: http://jsperf.com/jquery-document-cached-vs-uncached/3 (edit: the title holds "jsquery" because that was the original test, my edit contains vanilla javascript, the framework makes no difference)
This really makes me curious. Basically I am introducing a new variable into the equation, how can that make things faster instead of slower?
As far as I know, "print a" should be better than "b = a; print b" (figure of speach)
What's different in this case?

document is not like an ordinary Javascript variable. There's no telling what odd magic is happening under the covers when accessing its attributes, especially the DOM, which may be created on demand from internal browser structures.

I believe I found an explanation here (the emphasis on the last part is mine):
Store pointer references to in-browser objects. Use this technique to
reduce DOM traversal trips by storing references to browser objects
during instantiation for later usage. For example, if you are not
expecting your DOM to change you should store a reference to DOM or
jQuery objects you are going to use when your page is created; if you
are building a DOM structure such as a dialog window, make sure you
store a few handy reference to DOM objects inside it during
instantiation, so you dont need to find the same DOM object over an
over again when a user clicks on something or drags the dialog
window.If you haven’t stored a reference to a DOM object, and you need
to iterate inside a function, you can create a local variable
containing a reference to that DOM object, this will considerably
speed up the iteration as the local variable is stored in the most
accessible part of the stack.
So, if I understand correctly, caching the DOM in a local variable makes it easier to access in the memory stack, therefore increasing the speed of execution.

Related

Is it better to use a reference to a dom element inside a callback instead of retrieving it?

I'm not sure how to phrase this question concisely, so if it's been asked before (and I'm sure it has been) that's why I can't find the answer(s).
If I have something like the following code in Javascript/jQuery:
$('#my-clicky-thing').click(function() {
if ( document.getElementById('my-checkbox').checked ){
// whatever
}
}
...would it be more sensible / efficient to do this instead:
var myCheckbox = document.getElementById('my-checkbox');
$('#my-clicky-thing').click(function() {
if ( myCheckbox.checked ){
// whatever
}
}
The latter approach seems to me like it would be more efficient. I'm assuming that a reference to the checkbox is bound to the click callback function when it is created, so using the checkbox reference would be faster than having to call getElementById to fetch it.
I'm just using this as a simple example. I don't have any formal Javascript training, but in practice, I usually always go with the reference approach. I just never stopped to think if there are any drawbacks or gotchas with doing this.
The latter approach seems to me like it would be more efficient.
That depends on what you mean by "efficient." It's less memory-efficient, for instance. But unless you have millions of them, the memory impact is unlikely to matter.
I'm assuming that a reference to the checkbox is bound to the click callback function when it is created...
Yes, it is, because the callback is a closure over the context in which that variable exists.
... so using the checkbox reference would be faster than having to call getElementById to fetch it.
Infinitesimally, yes. getElementById is very fast, because the browser keeps an index of elements by their ID and so it's a very, very, very quick lookup.
A more complex DOM query would be slower, but clicks are nothing like time-sensitive, so it's extremely unlikely to matter. A slow query in relation to an event that happens a lot (like mousemove) would argue for caching the reference; otherwise, it really doesn't matter and the decision of whether to keep the reference vs. looking it up is probably best driven by other factors, such as whether the element may go away, whether the closure will otherwise be optimized away (e.g., nothing else in it), that sort of thing.
You are definitely correct. Looking for the element in the DOM on every click is less efficient using jQuery's $() (see note). Keeping a reference to it is always a good practice.
It is especially recommended if you are planning to look for it more than once and perform several actions on it.
The only drawback I can think of is that when done excessively you'll end up having lots of variables sitting around holding references.. So this one is up to you to consider in your implementation.
For example, if you have a lot of these elements that need to be referenced, hold a reference to their container instead of to each one of them. Finding them within their container is likely to be more efficient than searching the entire DOM.
Note: As #T.J.Crowder mentioned, getElementByID is fairly fast and you shouldn't worry about it in this case. My answer is general and especially referring the $() selector for jQuery.
It's kind of general rule imo : keep reference to object as long as you may require access to this object though it's different for Java/C# where garbage collector removes all objects that does not have references so if you keep reference to object - you keep object in memory even when you don't need it.
But in your case i believe it doesn't really matter as click is event that fires too rare to make big difference. It would make more sense if you would like to access 50 different dom elements like 10 000 times each.

caching object in DOM vs javascript variable

I've recently looked at some front end js code.
(1) In some cases the code creates a new JavaScript object from a JSON received from the back end. Then the newly created object is stored in a cache (say a map). This way the object would be cached on the front end for later use.
(2) I've also seen instances when the new JavaScript object (called eventObject here) is stored in the DOM like this: $(this).data('eventObject', eventObject);
Does it matter which way you store the data? I would personally cache eventObject in a JavaScript cache object (ie make your own cache class or a map). Isn't it simpler to cache like this than mess with the DOM and then you have to remember where you put what?
In my searches I've looked at XML DOM vs Object in Javascript
Isn't it simpler to cache like this than mess with the DOM and then you have to remember where you put what?
jQuery's data method actually doesn't mess with the DOM, it is just a convenient way to reference data objects by DOM nodes.
Of course, if you "have to remember whery you put it" the DOM references are not the best way to reference your objects. If a simple cache object seems cleaner to you, it probably will be cleaner.

Node Cloning and Removing

What happens when a cloned node is not attached to any DOM. Suppose I have a JavaScript code Clone a DOM element every time it's method is called.I need this object temporarily, I don't need to add it to DOM component. But I am worried if it creates performance issue in client side so I am wondering what happens to the object cloned by javascript.
As soon as the JavaScript Engine detects you are done with that object its garbage collector will clean it up for you. As long as the object isn't in the global scope or is able to be referenced it will be cleaned on a garbage collector pass.
It depends on how you are assigning the clone, but it's possible they could accumulate in memory.
No code = no idea.

Can jQuery.data cause a memory leak?

Would the following piece of code create a memory leak.
According to the jQuery documentation use of the data function avoids memory leaks. It would be useful to confirm whether the following is safe.
var MyClass = function(el) {
// Store reference of element in object.
this.element = $(el);
};
// Store reference of object in element.
$('#something').data('obj', new MyClass('#something'));
Obviously the code as it stands would take up extra memory as long as the DOM element is still connected to the DOM. But I'm guessing you're asking whether it would continue using extra memory after the DOM element is no longer in use.
Update: Thanks to Joey's answer (which he has since deleted), I spent some time reading up on memory leaks in javascript, and it appears my assumptions in the paragraph below are incorrect. Because DOM elements don't use pure garbage collection, a circular reference like this would normally prevent both the DOM element and the javascript object from ever being released. However, I believe the remainder of this answer is still correct.
Without a deep knowledge of how javascript engines implement garbage collection, I can't speak authoritatively on the topic. However, my general understanding of garbage collection makes me think that your code would be "safe" in the sense that after the #something element is removed from the DOM, the resulting MyClass object would only have a reference to an object that has no other connections. The graph algorithms of the garbage collector should be able to identify that the DOM element and its MyClass object are "floating in space" and unconnected to everything else.
Furthermore, jQuery goes out of its way to strip data and events that are associated with a given DOM element once it is removed from the DOM. From the documentation:
jQuery ensures that the data is removed when DOM elements are removed via jQuery methods, and when the user leaves the page.
So assuming you use jQuery consistently, you would only have a one-way reference once the object is removed from the DOM anyway, which makes it that much easier possible for the garbage collector to know it can get rid of these objects.
So as long as you don't have something else referencing the MyClass object once the DOM element is removed, you shouldn't have a memory leak.
I suppose it depends on the Javascritp engine.
You have have the question precisely enought to perform a test. I added a long string in the object and ran the potential leak in a large loop.
As a result, I don't think in leaks in IE8 nor in Chrome.
But I could not reproduce these leakeage patterns either.
This can lead to a memory leak.
the theory of jQuery.data method may use A Data inner class to cache data for the dom element.
of course,when you remove the cache data,jQuery will unreference the data.
but the inner cache is a increasing array,when you you it ,it will go upon.
so ,in the end,there will be very big cache array,which will lead memeory leak.
In a long run web app,this may leak memory crash.
The data attribute only stores string values.

Do I have to clean custom properties (Expandos) on window.onunload event?

In one article I have seen that it may be good to clear all expandos on window.unload event to prevent memory leaks.
I cannot understand why to do this.
Isn't the browser cleaning all the DOM and its relevant resources of it once you leave the page anyway?
Thanks,
burak ozdogan
Hey, great question. The problem is with circular references between JavaScript objects and DOM nodes.
Let's say you have a global JavaScript object which points to a DOM node and the node has an expando property back to the object. When the page unloads, the script engine "nulls-out" the JavaScript object so it no longer points to the DOM node. But, it cannot release the object from memory because there is still a reference to it (from the DOM). Then the script engine terminates.
Expando properties on the DOM are nothing but references to other objects. When the DOM is being cleaned up, it breaks those references but assumes that the objects are still being used. In this example, the DOM waits for the script engine to clean up the objects that belong to it, but the script engine has already terminated.
So, the problem is that the DOM only takes care of the memory that belongs to it and assumes the script engine will do the same.
I hope this helped.
See: http://msdn.microsoft.com/en-us/library/bb250448%28VS.85%29.aspx

Categories

Resources