JQuery selector - full or optimized scan? - javascript

Code example:
$JK("body *").each(function() { ... });
Will JQuery fill the elements' array first before calling each() or there is kinda LINQ-style optimization, so that function will be called during the DOM tree traversal? I guess that this optimization might (or not) be deployed into the JS engine. If so, how one can know if it is implemented for this or that engine/browser?

It builds the entire list first. I can't imagine how it could be done in the browser/JavaScript engine, though I guess it might be possible to make NodeList be lazy somehow.
The jQuery object looks like an Array instance (it isn't, but it tries to look like one), meaning that you can randomly-access elements by numeric index. It'd be quite a trick to make that be lazy.
Note that modern browsers support DOM-accessing functions that push a lot of the work down into the browser's internals, so that often — as, I suspect, in the case of your selector, which is really just
document.getElementsByTagName('body')[0].getElementsByTagName('*')
the browser hands back the complete list to jQuery. That's why I mentioned making the NodeList object be lazy, but I still think it'd be pretty hard given the semantics of JavaScript.

It fills the elements array first.
Since this is really just javascript and javascript is single threaded (except for web workers which are not being used here and can't access the DOM anyway), it happens like this:
This function call is executed to completion:
$JK("body *")
That function returns a jQuery object upon with the
.each()
method is called. In that method, it iterates through the array of DOM elements and calls the callback function once for each DOM element.

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.

Why cache jQuery objects?

So why are we supposed to cache jQuery objects?
In the following scenario:
var foo = $('#bar');
foo.attr('style','cool');
foo.attr('width','123');
$('#bar').attr('style','cool');
$('#bar').attr('width','123');
Why is the first option so much better than the second option?
If it's because of performance, how does it reduce usage?
Because the jQuery function has a lot of code in it, which involves unnecessary overhead if you execute it more than once with the same inputs expecting the same outputs. By caching the result, you store a reference to the exact element or set of elements you're looking for so you don't have to search the entire DOM again (even if it's a fairly fast search). In many cases (simple pages with small amounts of code) you won't notice a difference, but in the cases where you do it can become a big difference.
You can see this in action by testing your example in jsPerf.
You can also think of it as an example of the Introduce Explaining Variable refactoring pattern for readability purposes, particularly with more complex examples than the one in the question.
The jQuery selector $('#foo') searches the entire DOM for the matching element(s) and then returns the result(s).
Caching these results means that jQuery doesn't have to search the DOM every time the selector is used.
EDIT: document.getElementById() is what jQuery uses to search the DOM, but there's never enough jQuery.

Why is checking for an attribute using dot notation before removing faster than removing the attribute outright?

I asked this question, and it turned out that when removing an attribute from an element, checking whether the element exists first using elem.xxx!==undefined makes the runtime faster. Proof.
Why is it quicker? There's more code to go through and you'll have to encounter the removeAttribute() method whichever way you go about this.
Well, first thing you need to know is that elem.xxx is not the same as elem.getAttribute() or any other method relative to the attribute.
elem.xxx is a property of a DOM element while attribute and element on the HTML inside the DOM, both are similar but different. For exemple, take this DOM element: <a href="#"> and this code :
//Let say var a is the <a> tag
a.getAttribute('href');// == #
a.href;// == http://www.something.com/# (i.e the complet URL)
But let take a custom attribute : <a custom="test">
//Let say var a is the <a> tag
a.getAttribute('custom');// == test
a.custom;// == undefined
So you can't really compare the speed of both since they don't achieve the same result. But one is clearly faster since properties are a fast access data while attribute use the get/hasAttribute DOM functions.
Now, Why without the condition is faster? Simply because removeAttribute doesn't care is the attribute is missing, it check if it is not.
So using hasAttribute before removeAttribute is like doing the check twice, but the condition is a little slower since it need to check if the condition is satisfied to run the code.
I have a suspicion that the reason for the speed boost are trace trees.
Trace trees were first introduced by Andreas Gal and Michael Franz of the University of California, Irvine, in their paper Incremental Dynamic Code Generation with Trace Trees.
In his blog post Tracing the Web Andreas Gal (the co-author of the paper) explains how tracing Just-in-Time compilers works.
To explain tracing JIT compilers as sententiously as possible (since my knowledge about the subject isn't profound) a tracing JIT compiler does the following:
Initially all the code to be run is interpreted.
A count is kept for the number of times each code path is executed (e.g. the number of times the true branch of an if statement is executed).
When the number of times a code path is taken is greater than a predefined threshold the code path is compiled into machine code to speed up execution (e.g. I believe SpiderMonkey executes code paths executed more than once).
Now let's take a look at your code and understand what is causing the speed boost:
Test Case 1: Check
if (elem.hasAttribute("xxx")) {
elem.removeAttribute("xxx");
}
This code has a code path (i.e. an ifstatement). Remember that tracing JITs only optimize code paths and not entire functions. This is what I believe is happening:
Since the code is being benchmarked by JSPerf it's being executed more than once (an understatement). Hence it is compiled into machine code.
However it still incurs the overhead of the extra function call to hasAttribute which is not JIT compiled because it's not a part of the conditional code path (the code between the curly braces).
Hence although the code inside the curly braces is fast the conditional check itself is slow because it's not compiled. It is interpreted. The result is that the code is slow.
Test Case 2: Remove
elem.removeAttribute("xxx");
In this test case we don't have any conditional code paths. Hence the JIT compiler never kicks in. Thus the code is slow.
Test Case 3: Check (Dot Notation)
if (elem.xxx !== undefined) {
elem.removeAttribute("xxx");
}
This is the same as the first test case with one significant difference:
The conditional check is a simple non-equivalence check. Hence it doesn't incur the full overhead of a function call.
Most JavaScript interpreters optimize simple equivalence checks like this by assuming a fixed data type for both the variables. Since the data type of elem.xxx or undefined is not changing every iteration this optimization makes the conditional check even faster.
The result is that the conditional check (although interpreted) does not slow down the compiled code path significantly. Hence this code is the fastest.
Of course this is just speculation on my part. I don't know the internals of a JavaScript engine and I hence my answer is not canonical. However I opine that it is a good educated guess.
Your proof is incorrect...
elem.class !== undefined always evaluates to false and thus elem.removeAttribute("class") is never called, therefore, this test will always be quicker.
The correct property on elem to use is className, e.g.:
typeof elem.className !== "undefined"
As Karl-André Gagnon pointed out, accessing a [native] JavaScript property and invoking a DOM function/property are two different operations.
Some DOM properties are exposed as JavaScript properties via the DOM IDL; these are not the same as adhoc JS properties and require DOM access. Also, even though the DOM properties are exposed, there is not strict relation with DOM attributes!
For instance, inputElm.value = "x" will not update the DOM attribute, even though the element will display and report an updated value. If the goal is to deal with DOM attributes, the only correct method is to use hasAttribute/setAttribute, etc.
I've been working on deriving a "fair" micro-benchmark for the different function calls, but it is fairly hard and there is alot of different optimization that occurs. Here my best result, which I will use to argue my case.
Note that there is no if or removeAttribute to muddle up the results and I am focusing only on the DOM/JS property access. Also, I attempt to rule out the claim that the speed difference is merely due to a function call and I assign the results to avoid blatant browser optimizations. YMMV.
Observations:
Access to a JS property is fast. This is to be expected1,2
Calling a function can incur a higher cost than direct property access1, but is not nearly as slow as DOM properties or DOM functions. That is, it is not merely a "function call" that makes hasAttribute so much slower.
DOM properties access is slower than native JS property access; however, performance differs widely between the DOM properties and browsers. My updated micro-benchmark shows a trend that DOM access - be it via DOM property or DOM function - may be slower than native JS property access2.
And going back to the very top: Accessing a non-DOM [JS] property on an element is fundamentally different than accessing a DOM property, much less a DOM attribute, on the same element. It is this fundamental difference, and optimizations (or lack thereof) between the approaches across browsers, that accounts for the observed performance differences.
1 IE 10 does some clever trick where the fake function call is very fast (and I suspect the call has been elided) even though it has abysmal JS property access. However, considering IE an outlier or merely reinforcement that the function call is not what introduces the inherently slower behavior, doesn't detract from my primary argument: it is the DOM access that is fundamentally slower.
2 I would love to say DOM property access is slower, but FireFox does some amazing optimization of input.value (but not img.src). There is some special magic that happens here. Firefox does not optimize the DOM attribute access.
And, different browsers may exhibit entirely different results .. however, I don't think that one has to consider any "magic" with the if or removeAttribute to at least isolate what I believe to be the "performance issue": actually using the DOM.

Which is better - Ext.get() or document.getElementById()

What is the difference between Ext.get() and document.getElementById() in terms of performance? Will Ext.get() be slower as it may internally call document.getElementById() ? Or is there any specific advantage of using Ext.get() ?
The principle advantage of Ext.get over getElementById is that it returns to you an Ext.Element instance. This instance not only contains the DOM node reference that getElementById would give you but also significantly extends it - offering a suite of convenience methods, event normalization, and an ironing out of cross-browser differences.
On the surface getElementById may have some minuscule speed gain over Ext.get simply on the basis of one less function before getting to the same fundamental DOM call. However, in terms of overall performance what you do with the element after retrieval will likely have much more impact than the retrieval itself. Having the Ext.Element wrapper on hand may prove to be quite beneficial.
You may want to have a look at Ext.fly as well. This method is similar to Ext.get with exception that it returns to you a singleton Ext.Element instance. It won't be any good if you need to store the element for later use, but if you are doing simple, one-off operations against unique DOM nodes it may be cheaper than Ext.get.
document.getElementById() is native JavaScript and so will be faster than Ext.get()
Now why Ext.get() is there at all,
document.getElementById() returns a DOM element, while Ext.get() returns an Ext object which is apt for chaining purposes.
And this is also the reason why jQuery have a $("#elm_id"). Please note that Ext.get() is also much easier to type :)
Ext.get() allows for using a String ID, an existing HTMLElement, or a Ext.Element - so it's a little bit more flexible. document.getElementById() only accepts the String ID.
That said, I'd just use document.getElementById() if it meets your needs. It's native to the browser and should be a little faster - and it's one less call that you're chaining yourself to a specific JavaScript framework with.
In terms of performance, native JS functions will always be faster.
However, I am not saying not to use JS Libraries, they are great as they:
reduce the time when writing your code
it make your code more readable
you write less code (reducing file-size and download time)
And in the end, maybe you even save time because less code means faster download and in some cases it could even beat the performance.
So yeah, it is the same to use one over the other, since in one hand you save time by performance ("document.getElementById()") and in the other you reduce file size and download time ("Ext.get()").
You can use both and there shouldn't be any noticeable difference.
As others have eluded to here the method used depends upon need, if you just want to get a reference to the dom element for some non Ext purpose you may as well use the native function, but if you intend to perform actions on the returned object in an Ext context, then Ext.get will return you an Element reference which offers additional methods.
Ext.get is shorthand for Ext.ComponentManager.get and whilst it is a call to a library function and may be less efficient is should be noted that there are ~180 methods available on Ext.Element, so if you need these it may be worth including wrapper call.
As owlness has mentioned, Ext.fly() is designed when you need to perform a single function on an element, eg. Ext.fly("myDiv").hide(); whereas Ext.get() is intended when you need a get a reference to an element for later use, eg. var something = Ext.get("myDiv"); then perhaps something.sort(); something.badger(); return something;
I'm unfamiliar with the Ext library, but with vanilla Javascript, there's only a handful of ways to get a particular element; you can get it by its ID, search for it after getting all elements by a tag name (this is how JQuery gets elements by class name I believe), or, new to HTML5, get an element by a class name. There's a few other ways if you get creative ;)
Just getting it by ID is the quickest, assuming you didn't save a local reference.
So, if all you're trying to do is get an element without doing whatever Ext.js does via that function call, vanilla Javascript will be much faster.

Should I check for a element on a page before calling the Jquery plugin or call it and allow it to fail if not there

I have recently been wondering what would be the most friendly/efficient way to use plugins that have been bundled together to leverage caching. Are plugins are tied to HTML modules that are used sporadically in the site and have been called by using this kind of pattern:
if($('.moduleClass').length) {
$('.moduleClass').modulePlugin();
}
So we check for the module before we call the plugin. I have been wondering if this is the best solution or should I just be allowing jQuery to handle the fail if the browser doesn't find the element.
$('.moduleClass').modulePlugin();
Any idea, thoughts and experiences would be greatly received.
Thanks,
Ad
Doing 2 DOM lookups, is slower than doing 1.
Let jQuery handle it, there shouldn't be an error if there are no elements with the class 'moduleClass', nothing should happen.
I'd recommend not checking for existing explicitly. Just try to find a DOM element and call methods on it. Even if the element does not exist. jQuery handles this for you.
About speed: You're doing two DOM lookups in your first example, which is obviously slower than your second example. And even if you cached the jQuery object in the first example, it's still one lookup in each example.
Well, from the start, you're already calling .length on what could have been an empty set. jQuery lets you do that because it handles stuff like non-existent elements correctly.
Now, whether or not your plugin does the same is a whole different question. Nonetheless, I recommend against checking first anyway. If the plugin does not handle empty sets properly (especially since jQuery -- which it's built on -- does), I'd think again about using it.
I learned that if the plugin sucks it makes sense to check for it.
But if the plugin itself does a check via length or each(). There is nothing to gain by checking with length.

Categories

Resources