document.querySelectorAll polyfill - javascript

I was asked in a telephonic interview to write a document.querySelector/ document.querySelectorAll polyfill, utilizing the following
document.getElementById
document.getElementsByClassName
document.getElementsByTagName
The polyfill should be able to take any combination of css selectors, for example .foo p.bar.baz span.qax.
I could not come up with a proper solution.
My approach ...
... was to parse the selector and start for the right.
With respect to .foo p.bar.baz span.qax
I wanted to parse the selector in something like ['.foo', ['p', '.bar',
'.baz'], ['span', '.qax']
take the right most element,
if it is an array, for the right most element of the array, fetch nodes with the available methods.
otherwise for the right most element of the array, fetch nodes with the available methods
and filter the available node with respect to the remaining selectors in the left
Where did I fail?
I could not figure out the regex to parse the selector
I guess I should have started from the left instead of right of the parsed selectors.
I searched for document.queryselector polyfill but could not comprehend {x:expression(document.__qsaels.push(this))} in most of the available solutions.
Any pointer would be helpful. Thanks!
Updates w.r.t. comments
Thanks everyone for your suggestions/comments.
#Sitian Liu, my primary query is 'how to implement querySelectorAll with strictly document.getElementById, document.getElementsByClassName, document.getElementsByTagName' I thought I could club {x:expression(document.__qsaels.push(this))} Thanks #RobG for the pointer to What does {x:expression(...)} do?.
#SravanS, I sorry, I don't know what is your definition of heavy, but the selector that was given to me had classes, tags, and child selector.
Polyfill intentionally omits attribute selectors
#guest271314 I don't remember if attribute selector was present. I guess it was intentionally omitted
#SravanS I appreciate your comments, but I am afraid to state, that you are assuming too much. Interviewer did want to dry run the code with respect to an HTML markup.
#SravanS #jfriend00 I am aware of sizzle, I thought I could get easy to comprehend answer here in StackOverflow, than reading through a 2242 lines of code. :)
#RobG echoed my concerns.
After going through all the comments, I am wondering if this question should be part of an 30 mins telephonic interview process, that too when you have to code it live in a Google Doc.

Where did I fail?
I could not figure out the regex to parse the selector
I believe in Google interview in 2017, the interviewer specifically told me “we are not looking for regex experts, so don’t invest time there”
In my case they were expecting me to break down the problem into simpler ones, I did this. I wrote seperate helper functions to do multiple things. And the unit functions which actually did finding part as leveregeable code, to be reused in all helpers recursively. The interviewer liked this and I cleared that round.
I will update the solution here in a week. In a gist, first you need to split the strings by spaces and > child selectors. For this splitting too, you can write a O(n) for-loop to go through the whole string. And not use the JS .split (not because it’s algorithm related, but because splitting that way will need further logic) For example, create child arrays only when you find one >.
Selectors on left has to be found. So I started with left first. I vaguely remember using t

Related

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.

jQuery Class Selectors: With or Without tagname?

I'm trying to find a definitive answer to the old question "should i use a tag name when selecting with a class?"
Everywhere i look on the web for jQuery best practices, there is nearly always a point of using jQuery("tag.className"); because this uses getElementByTagName first.
So I've set up a benchmark on jsPerf to check. I've used the source markup from my website so its more of a real world test and run the benchmark on all modern browsers and apart from Chrome and Opera, all the other modern browsers say that jQuery(".className"); is an order of magnitude faster even though this goes against nearly everything i've read in books and tutorials online. I assume its faster because those browsers support getElementByClassName natively.
Here's the benchmark:
http://jsperf.com/length-detection
What do you think is best?
Many thanks
Chris
If you are really after performance, you should not use jQuery at all for querying elements. See this jsperf: http://jsperf.com/jquery-selecting-by-class
There we can talk about "magnitudes". Honestly, without looking into the current jQuery source I can't tell what jQuery does under the hood. Even if it's using getElementsByClassNames it will have little and zero effect on overall performance due to all the blood and overhead that comes along jQuery. Anyway, the basic rule for querying elements is simple: Don't be overspecific. CSS Selectors work from right to left, so when we have a query like element.classname, most engines will first grab all elements with the classname of classname and then filter out the nodes which also belong the to element type of element.

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.

Good ways to improve jQuery selector performance?

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I'm looking for any way that I can improve the selector performance of a jQuery call. Specifically things like this:
Is $("div.myclass") faster than $(".myclass")
I would think it might be, but I don't know if jQuery is smart enough to limit the search by tag name first, etc. Anyone have any ideas for how to formulate a jQuery selector string for best performance?
There is no doubt that filtering by tag name first is much faster than filtering by classname.
This will be the case until all browsers implement getElementsByClassName natively, as is the case with getElementsByTagName.
In some cases, you can speed up a query by limiting its context. If you have an element reference, you can pass it as the second argument to limit the scope of the query:
$(".myclass", a_DOM_element);
should be faster than
$(".myclass");
if you already have a_DOM_element and it's significantly smaller than the whole document.
As Reid stated above jQuery is working from the bottom up. Although
that means $('#foo bar div') is a
lot slower than $('bar div #foo')
That's not the point. If you had #foo you wouldn't put anything before it in the selector anyway since IDs have to be unique.
The point is:
if you are subselecting anything from an element with an ID then select the later first and then use .find, .children etc.: $('#foo').find('div')
your leftmost (first) part of the selector can be less efficient scaling to the rightmost (last) part which should be the most efficient - meaning if you don't have an ID make sure you are looking for $('div.common[slow*=Search] input.rare') rather than $('div.rare input.common[name*=slowSearch]') - since this isn't always applicable make sure to force the selector-order by splitting accordingly.
In order to fully comprehend what is faster, you have to understand how the CSS parser works.
The selector you pass in gets split into recognizable parts using RegExp and then processed piece by piece.
Some selectors like ID and TagName, use browser's native implementation which is faster. While others like class and attributes are programmed in separately and therefore are much slower, requiring looping through selected elements and checking each and every class name.
So yes to answer your question:
$('tag.class') is faster than just $('.class'). Why?
With the first case, jQuery uses the native browser implementation to filter the selection down to just the elements you need. Only then it launches the slower .class implementation filtering down to what you asked for.
In the second case, jQuery uses it's method to filter each and every element by grabbing class.
This spreads further than jQuery as all javascript libraries are based on this. The only other option is using xPath but it is currently not very well supported among all browsers.
Here is how to icrease performance of your jQuery selectors:
Select by #id whenever possible (performance test results ~250 faster)
Specify scope of your selections ($('.select', this))
I'll add a note that in 99% of web apps, even ajax heavy apps, the connection speed and response of the web server is going to drive the performance of your app rather than the javascript. I'm not saying the you should write intentionally slow code or that generally being aware of what things are likely to be faster than others isn't good.
But I am wondering if you're trying to solve a problem that doesn't really exist yet, or even if you're optimizing for something that might change in the near future (say, if more people start using a browser that supports getElementsByClassName() function referred to earlier), making your optimized code actually run slower.
Another place to look for performance information is Hugo Vidal Teixeira's Performance analysis of selectors page.
http://www.componenthouse.com/article-19
This gives a good run down of speeds for selector by id, selector by class, and selector prefixing tag name.
The fastest selectors by id was: $("#id")
The fastest selector by class was: $('tag.class')
So prefixing by tag only helped when selecting by class!
I've been on some of the jQuery mailing lists and from what I've read there, they most likely filter by tag name then class name (or vice versa if it was faster). They are obsessive about speed and would use anything to gain a smidgen of performance.
I really wouldn't worry about it too much anyway unless you are running that selector thousands of times/sec.
If you are really concerned, try doing some benchmarking and see which is faster.
Consider using Oliver Steele's Sequentially library to call methods over time instead of all at once.
http://osteele.com/sources/javascript/sequentially/
The "eventually" method helps you call a method after a certain period of time from its initial call. The "sequentially" method lets you queue several tasks over a period of time.
Very helpful!
A great tip from a question I asked: Use standard CSS selectors wherever possible. This allows jQuery to use the Selectors API. According to tests performed by John Resig, this results in near-native performance for selectors. Functions such as :has() and :contains() should be avoided.
From my research support for the Selectors API was introduced with jQuery 1.2.7, Firefox 3.1, IE 8, Opera 10, Safari 3.1.
If I am not mistaken, jQuery also is a bottom up engine. That means $('#foo bar div') is a lot slower than $('bar div #foo'). For example, $('#foo a') will go through all of the a elements on the page and see if they have an ancestor of #foo, which makes this selector immensely inefficient.
Resig may have already optimized for this scenario (it wouldn't surprise me if he did - I believe he did in his Sizzle engine, but I am not 100% certain.)
I believe that selecting by ID first is always faster:
$("#myform th").css("color","red");
should be faster than
$("th").css("color","red");
However, I wonder how much chaining helps when starting with the ID? Is this
$("#myform").find("th").css("color","red")
.end().find("td").css("color","blue");
any faster than this?
$("#myform th").css("color","red");
$("#myform td").css("color","blue");

Categories

Resources