Speed difference between very similar jQuery expressions in IE - javascript

In IE, compare the speed of execution of an expression along the lines of
$('div.gallery div.product a");
to the very similar
$('div.gallery').find("div.product").find("a");
Sometimes the second variant runs faster, sometimes slower. Often the speed difference is a factor of 2 or more. What is going on?

The first variant will do the following:
Find all anchor tags in the page
Only leave the ones with ancestor div.product
Only leave the ones with ancestor div.gallery
The second one
Find elements with class .gallery and tag div
Search for div.product in their descendants
Search for anchor tags in their descendants
So the first one will search for elements from right to left, while the second one will search them from left to right.
Which is faster depends on your site structure but the first one is the recommended way, because browsers match CSS selector the same way.
If you want to increase speed make sure that the rightmost selector is as specific as possible.
e.g.: in this case you can add a special class for your anchor tags like .gallery-link and then your query will become a simple a.gallery-link which in IE will invoke a getElementsByTagName function for the anchor tags then they will be filtered by their class name. Notice that because you don't have to traverel up the DOM tree your query becomes significantly faster. The cost is a bit more complex markup. For costly queries it may worth it.

Related

Should I detach elements from the DOM while I apply many styles to them?

I'm concerned about performance and best practices.
So I'm building graphical UI and learned that I shouldn't call jQuery.append() a gazillion times when creating many small elements. So I got that covered by document.createDocumentFragment(). I'm adding elements to that, then once done, I insert the fragment to the DOM (with appendChild),
Then, in another pass I calculate where each element should be. Everything is absolutely positioned and will receive x and y values via CSS transform. Unfortunately, for these calculations I need the elements in the DOM since some of them contan random length text, and I need to measure widht/height. Otherwise I would perform step 3 on the document fragment directly, before it's even inserted into the DOM.
In the final pass I apply the calculated styles over everything with jQuery.css() (will likely replace with setAttribute instead of jQuery) as part of a loop (many calls to that, unfortunately - every element has different x/y). Should I detach the container that holds all my elements while I apply the styles, then reattach it to the DOM?
Due to lack of interest I decided to test it myself. Pulling an element of 700+ articles (15000 nodes), applying various CSS on the majority of them, then putting the element back into the page was actually slower by 50%. Let the browser do its job by only showing the results of changed attributes when Layout is needed.
I read the advice somewhere to remove the element from the DOM while working on it. While this could be true when appending elements to it, this does not hold true for style manipulations.

Right to Left jQuery Selectors not working

In reading post on StackOverflow about jQuery Selector performance, I keep reading the same thing over and over saying jQuery uses a Bottom up or Right to Left approach to selectors.
Take this example...
$("#dnsTitle a.save").removeClass("disabled");
According to what I have been reading it is better performance to use this instead...
$("a.save #dnsTitle").removeClass("disabled");
The problem I am running into is this does not even work at all! Can someone clarify the real best method for doing selectors?
I am working on an existing project that has some really long selectors and I am trying to improve them where I can but it seems I am getting bad information or outdated. I am using jQuery 2.0
The concept of "Bottom Up/Right to Left/Leaf to Root" is only related to the implementation of the selector parser and not the order of the selectors in usage.
Usage:
From the usage standpoint, selectors are "read" left to right, where your first selector is your root, and the succeeding selectors your descendants. The elements that match the last selector are returned. And so:
#dnsTitle a.save - looks for an element that has an id of dnsTitle and from there, looks for a decendant a element with class save. You end up with the a elements with the class save.
a.save #dnsTitle - looks for an a element with class save and from that, finds a decendant with an id of dnsTitle. You end up with whatever elements with the id dnsTitle
Parsing:
Now from the parsing point of view, there's 2 common ways you approach parsing a selector string, and they're the "Top-down" and the "Bottom-Up":
Top-down / Root to Leaves / Left to Right
If you've been through a Data Structures course, then this is how you normally parse a tree. You find the node where you want to start, which would be your first selector. Then you work your way down in finding the succeeding nodes.
A problem in this approach is that it uses a recursive approach and uses a lot of memory, especially if your tree is huge. Also, the issue of back-tracking is a problem since the succeeding selectors are descendants, and matches may vary in depth. The next selector might match a great^N grandchild. Recursion goes N steps deep to find that great^N child and take N steps to return back up.
Bottom-Up / Right to Left / Leaves to Root
With this approach, the parser looks for all elements that match the last selector and you end up with an array of matches. With that array of matches, you filter them if they match the succeeding previous selectors.
The advantage of this approach is that you have a fixed array to work on, and not a variable-depth tree. Also, you are filtering linearly since a node, in this case, can only have one parent in contrast to top-down which deals with multiple children. This also means you only need loops to do the job, not recursion. One loop can go over each result, and the other, nested, to go through each ancestor if it matches the succeeding previous selectors.

Determine the character index of DOM element inside its owner document's html?

Primarily, I need to convert selection ranges to indices in the source HTML. I was thinking there's a couple ways to do it manually, but is there a built in way to do it?
Some ideas:
Clone the document. Remove the element and its subsequent siblings, and remove all the subsequent siblings of each of its ancestors. Then you just get the document HTML and get its length. o_O
render the tags, text, etc to HTML myself, walking down the DOM tree. Also o_O
The performance could be improved by caching results. Then, if an ancestor already knows its position, it's a bit faster to compute the childs. But then maintaining the cache is another thing.
What about adding a unique ID or class to it and then search for that in the whole document string?

Is there an efficiency difference between finding by id and finding by class with JavaScript/jquery?

Is there an efficiency difference between finding by id and finding by class with JavaScript/jquery?
Is one better than the other? If so is it because indexes of ID or Class are made in the DOM somewhere?
Does it end up not mattering much?
Finding by ID is always faster, no matter where (getElementById(), $('#id'), or even in regular CSS).
Since ID's are unique per page, they're much faster to find.
In addition, when using $('#id'), jQuery will map that back to the built-in getElementById(), which is the fastest way to query the DOM.
Well, logically speaking, an ID would be more efficient, as there is (should be) only one of it, so once it finds it, it will stop searching. However I am not familiar with the jQuery source, I don't know how it actually works, that's from a logic perspective.
For most browsers, the difference in speed between searching by id and searching by class name depends on how many elements have a given class. At best, there will be only one such element, and the search speed ought to be the same. At worst, there are a bazillion elements with a given class. Typically, though, you shouldn't have to worry about the speed of searching through 10-20 elements containing the same class.
A critical caveat, though: MSIE <= 8 has no native getElementsByClassName, so jQuery has to fall back to a full DOM tree search unless, e.g., the element name of the wanted element is also provided. Even then. $('div.myclass') may not be much help if your document is large and exceedingly div-happy. Benchmarking is really the only way to find out.

optimizing jQuery Selectors - Which is faster?

Are selectors or functions faster in jQuery? Example:
$('#something div.else'); // find multiple divs with class .else
or
$('#something').children('div.else');
I'm trying my best to optimize a page with hundreds of returned elements that seems to hang on a certain crappy computer here in the office (that must use Internet Explorer ::shudder::).
Well in this case, the second's faster, but, they're not equivalent. The first finds any descendant div.else, the other finds only direct children that are div.else.
It depends on your DOM as to which is faster, the equivalent of the second would be this:
$('#something > div.else');
This uses the child selector. They should be very, very close, and in any case, I doubt a selector descending from an ID is your problem area, I think you'll find the vast majority of your time in JS is spent elsewhere.
For diagnosing speed issues, get a profiler, for IE specifically there's a fantastic free one called dynaTrace AJAX Edition. Grab it, follow the short tutorials on their site...you'll find where your pain areas in IE are pretty quickly.
Although I haven't checked with the jQuery code, I think the difference should be negligable between your two examples - although the first one should run a little faster.
The problem with old IE versions is that they do not support a native way to fetch items based on class names. In this case, jQuery has to execute a regulra expression on each class attribute of each element contained.
If it is possible in your case, you might gain quite a lot performance when being able to select on an unusual tagname:
$("#container blockquote.else")
and ideally,leave away the class name.
EDIT: just saw the answer from Nick and he's right, the scond one only has to check the direct children. The equivalent first one would be:
$("#container > div.else")
In your specific example, your first example of
$('#something div.else');
gets optimized through Sizzle (which is delivered within the jQuery lib) into
$('#something').find('div.else');
without that optimization, it would be slower, since the selector engine sizzle does work from right to left. So, it would match all divs with the class else and would then check which of those has #something as parent.
edit
The Sizzle optimazation is slower
anyway, since it took a while until
that task is completed and some
functions are called on the way
In general, using jQuery functions is a lot faster. For instance jQuerys .eq() function will use an array slice to reduce a wrappet set of jQuery objects, whereas :eq() selector will invoke sizzle.
If in your example, div.else elements are direct children of #something, .children() will beat .find() since .find() will also lookup all descendants (and their childs).
If I understand correctly you need the fastest way to get #something div.else in IE6. Since jQuery uses Sizzle, the way it will find that is first find all div's, then filter by the ones with the else class, and has an ancestor with the #something id.
Your second example will be faster if it contains few children, slower if it contains many.
A suggestion you could try would be to use another tag type instead of div, one that isn't used in your page, say blockquote. Just reset it's styles with css so it looks like a normal div, then change your selector to #something blockquote.else which should be tons faster.

Categories

Resources