JavaScript - DOM Selector Engine - javascript

Is there any selector engine for DOM elements like jQuery which offers no other extended methods like .bind, .css etc? What I mean is, a selector which just return found elements, nothing more. I tried to modify the jQuery, removed methods to get only the function that returns elements, but I got errors.
Thanks in advance!

Have you looked at sizzle -
http://sizzlejs.com/
I believe it is the selector engine that jQuery uses.

If you code is intended to work only in modern browsers and the set of possible selectors is relatively simple (A.classA B.classB or something) you can use document.querySelectorAll with a thin wrapper over it or even do not use any frameworks at all.
As for old browsers, well, you always can try to implement it yourself, if size is so crucial for you. You can choose a tiny set of simple CSS selectors and use only them.
But, as well ipr101, I guess it will be better to use production-ready solution like sizzle.

Yes, there are many tiny JavaScript selector engines, like:
Quicksand
Qwery
Sizzle
Slick
uSelector
Zest
I'd recommend Quicksand, because it seems to be the fastest one (see this or this test).

Related

Is jQuery traversal preferred over selectors?

Is using $("#vacations").find("li").last() is a better practice than $("#vacations li:last")?
Background and my thoughts:
I was playing with a nice interactive try jQuery tutorial and one of the tasks says:
As you are looking through your code, you notice that someone else is selecting the last vacation with: $("#vacations li:last"). You look at this and you think, "Traversal would make this way faster!" You should act on those thoughts, refactor this code to find the last li within #vacations using traversal instead.
Why would I think so? For me usage of selectors looks a bit higher level than traversing. In my mind when I am specifying a selector it is up to jQuery how to better get the single result I need (without need in returning interim results).
What is that extra overhead of using composite selectors? Is it because current implementation of selectors logic just parses the string and uses the traversal API? Is parsing a string that slow? Is there a chance that a future implementation will use that fact that it does not need to return interim results and will be faster than traversal?
There's no cut and dry answer to this, but with respect to the :last selector you're using, it's a proprietary extension to the Selectors API standard. Because of this, it isn't valid to use with the native .querySelectorAll method.
What Sizzle does is basically try to use your selector with .querySelectorAll, and if it throws an Exception due to an invalid selector, it'll default to a purely JavaScript based DOM selection/filtering.
This means including selectors like :last will cause you to not get the speed boost of DOM selection with native code.
Furthermore, there are optimizations included so that when your selector is very simple, like just an ID or an element name, the native getElementById and getElementsByTagName will be used, which are extremely fast; usually even faster than querySelectorAll.
And since the .last() method just grabs the last item in the collection instead of filtering all the items, which is what Sizzle filters normally do (at least they used to), that also will give a boost.
IMO, keep away from the proprietary stuff. Now that .querySelectorAll is pretty much ubiquitous, there are real advantages to only using standards-compliant selectors. Do any further filtering post DOM selection.
In the case of $("#vacations").find("li"), don't worry about the interim results. This will use getElementById followed by getElementsByTagName, and will be extremely fast.
If you're really super concerned about speed, reduce your usage of jQuery, and use the DOM directly.
You'll currently find notes in the docs for selectors like :last, that warn you about the performance loss:
Because :last is a jQuery extension and not part of the CSS specification, queries using :last cannot take advantage of the performance boost provided by the native DOM querySelectorAll() method. To achieve the best performance when using :last to select elements, first select the elements using a pure CSS selector, then use .filter(":last").
But I'd disagree that .filter(":last") would be a good substitute. Much better would be methods like .last() that will target the element directly instead of filtering the set. I have a feeling that they just want people to keep using their non-standards-compliant selectors. IMO, you're better of just forgetting about them.
Here's a test for your setup: http://jsperf.com/andrey-s-jquery-traversal
Sizzle, jQuery's selector engine, parses the string with regex and tries to speed up very basic selectors by using getElementById and getElementsByTagName. If your selector is anything more complicated than #foo and img, it'll try to use querySelectorAll, which accepts only valid CSS selectors (no :radio, :eq, :checkbox or other jQuery-specific pseudo-selectors).
The selector string is both less readable and slower, so there's really no reason to use it.
By breaking the selector string up into simple chunks that Sizzle can parse quickly (#id and tagname), you're basically just chaining together calls to getElementById and getElementsByTagName, which is about as fast as you can get.

Can I force jQuery to use Sizzle to evaluate a selector without using non-standard selectors?

In modern browsers, jQuery makes use of document.querySelectorAll() to boost performance when valid CSS selectors are used. It falls back to Sizzle if a browser doesn't support the selector or the document.querySelectorAll() method.
However, I'd like to always use Sizzle instead of the native implementation when debugging a custom selector. Namely, I'm trying to come up with an implementation of :nth-last-child(), one of the CSS3 selectors that are not supported by jQuery. Since this selector is natively supported by modern browsers, it works as described in the linked question. It is precisely this behavior that's interfering with debugging my custom selector, though, so I'd like to avoid it.
A cheap hack I can use is to drop in a non-standard jQuery selector extension, thereby "invalidating" the selector so to speak. For example, assuming every li:nth-last-child(2) is visible, I can simply drop that in, turning this:
$('li:nth-last-child(2)').css('color', 'red');
Into this:
$('li:nth-last-child(2):visible').css('color', 'red');
This causes it to always be evaluated by Sizzle. Except, this requires that I make an assumption of my page elements which may or may not be true. And I really don't like that. Not to mention, I dislike using non-standard selectors in general unless absolutely necessary.
Is there a way to skip the native document.querySelectorAll() method in browsers that support it and force jQuery to use Sizzle to evaluate a selector instead, that preferably doesn't employ the use of non-standard selectors? Likely, this entails calling another method instead of $(), but it's much better than a selector hack IMO.
You could just set it to null before jQuery loads so it thinks it's not supported:
document.querySelectorAll = null;
//load jquery, will trigger not supported branch
//Optionally restore QSA here (save a reference) if needed
This is supposed to make this evaluate to false
Demo: http://jsbin.com/asipil/2/edit
Comment out the null line and rerun, and you will see it will turn red.
Since you're developing the code for the selector yourself, could you not simply give it a custom name for the duration of the development cycle? Maybe give it your own vendor prefix or something? -bolt-nth-last-child()
That way, you'll know the browser definitely won't support it, so it should always fall into using Sizzle.
When you're done with the development cycle, you can drop the -bolt- prefix.
I know that's more of a work-around than an answer to the question, but it seems like the simplest solution to me.
It looks to be that jQuery.find defaults to sizzle. This will save you from destroying your environment by setting a native function to null.
https://github.com/jquery/jquery/blob/master/src/sizzle-jquery.js#L3
So you should be able to do the following and it will always go through sizzle.
$.find('li:nth-last-child(2)')

jQuery vs document.querySelectorAll

I heard several times that jQuery's strongest asset is the way it queries and manipulates elements in the DOM: you can use CSS queries to create complex queries that would be very hard to do in regular javascript .
However , as far as I know, you can achieve the same result with document.querySelector or document.querySelectorAll, which are supported in Internet Explorer 8 and above.
So the question is this: why 'risk' jQuery's overhead if its strongest asset can be achieved with pure JavaScript?
I know jQuery has more than just CSS selectors, for example cross browser AJAX, nice event attaching etc. But its querying part is a very big part of the strength of jQuery!
Any thoughts?
document.querySelectorAll() has several inconsistencies across browsers and is not supported in older browsersThis probably won't cause any trouble anymore nowadays. It has a very unintuitive scoping mechanism and some other not so nice features. Also with javascript you have a harder time working with the result sets of these queries, which in many cases you might want to do. jQuery provides functions to work on them like: filter(), find(), children(), parent(), map(), not() and several more. Not to mention the jQuery ability to work with pseudo-class selectors.
However, I would not consider these things as jQuery's strongest features but other things like "working" on the dom (events, styling, animation & manipulation) in a crossbrowser compatible way or the ajax interface.
If you only want the selector engine from jQuery you can use the one jQuery itself is using: Sizzle That way you have the power of jQuerys Selector engine without the nasty overhead.
EDIT:
Just for the record, I'm a huge vanilla JavaScript fan. Nonetheless it's a fact that you sometimes need 10 lines of JavaScript where you would write 1 line jQuery.
Of course you have to be disciplined to not write jQuery like this:
$('ul.first').find('.foo').css('background-color', 'red').end().find('.bar').css('background-color', 'green').end();
This is extremely hard to read, while the latter is pretty clear:
$('ul.first')
.find('.foo')
.css('background-color', 'red')
.end()
.find('.bar')
.css('background-color', 'green')
.end();
The equivalent JavaScript would be far more complex illustrated by the pseudocode above:
1) Find the element, consider taking all element or only the first.
// $('ul.first')
// taking querySelectorAll has to be considered
var e = document.querySelector("ul.first");
2) Iterate over the array of child nodes via some (possibly nested or recursive) loops and check the class (classlist not available in all browsers!)
//.find('.foo')
for (var i = 0;i<e.length;i++){
// older browser don't have element.classList -> even more complex
e[i].children.classList.contains('foo');
// do some more magic stuff here
}
3) apply the css style
// .css('background-color', 'green')
// note different notation
element.style.backgroundColor = "green" // or
element.style["background-color"] = "green"
This code would be at least two times as much lines of code you write with jQuery. Also you would have to consider cross-browser issues which will compromise the severe speed advantage (besides from the reliability) of the native code.
If you are optimizing your page for IE8 or newer, you should really consider whether you need jquery or not. Modern browsers have many assets natively which jquery provides.
If you care for performance, you can have incredible performance benefits (2-10 faster) using native javascript:
http://jsperf.com/jquery-vs-native-selector-and-element-style/2
I transformed a div-tagcloud from jquery to native javascript (IE8+ compatible), the results are impressive. 4 times faster with just a little overhead.
Number of lines Execution Time
Jquery version : 340 155ms
Native version : 370 27ms
You Might Not Need Jquery provides a really nice overview, which native methods replace for which browser version.
http://youmightnotneedjquery.com/
Appendix: Further speed comparisons how native methods compete to jquery
Array: $.inArray vs Array.indexOf: Jquery 24% slower
DOM: $.empty vs Node.innerHtml: Jquery 97% slower
DOM: $.on vs Node.addEventListener: Jquery 90% slower
DOM: $.find vs Node.queryselectorall: Jquery 90% slower
Array: $.grep vs Array.filter: Native 70% slower
DOM: $.show/hide vs display none: Jquery 85% slower
AJAX: $.ajax vs XMLHttpRequest: Jquery 89% slower
Height: $.outerHeight vs offsetHeight: Jquery 87% slower
Attr: $.attr vs setAttribute: Jquery 86% slower
To understand why jQuery is so popular, it's important to understand where we're coming from!
About a decade ago, top browsers were IE6, Netscape 8 and Firefox 1.5. Back in those days, there were little cross-browser ways to select an element from the DOM besides Document.getElementById().
So, when jQuery was released back in 2006, it was pretty revolutionary. Back then, jQuery set the standard for how to easily select / change HTML elements and trigger events, because its flexibility and browser support were unprecedented.
Now, more than a decade later, a lot of features that made jQuery so popular have become included in the javaScript standard:
Instead of jQuery's $(), you can now now use Document.querySelectorAll()
Instead of jQuery's $el.on(), you can now use EventTarget.addEventListener()
Instead of jQuery's $el.toggleClass(), you can now use Element.classList.toggle()
...
These weren't generally available back in 2005. The fact that they are today obviously begs the question of why we should use jQuery at all. And indeed, people are increasingly wondering whether we should use jQuery at all.
So, if you think you understand JavaScript well enough to do without jQuery, please do! Don't feel forced to use jQuery, just because so many others are doing it!
That's because jQuery can do much more than querySelectorAll.
First of all, jQuery (and Sizzle, in particular), works for older browsers like IE7-8 that doesn't support CSS2.1-3 selectors.
Plus, Sizzle (which is the selector engine behind jQuery) offers you a lot of more advanced selector instruments, like the :selected pseudo-class, an advanced :not() selector, a more complex syntax like in $("> .children") and so on.
And it does it cross-browsers, flawlessly, offering all that jQuery can offer (plugins and APIs).
Yes, if you think you can rely on simple class and id selectors, jQuery is too much for you, and you'd be paying an exaggerated pay-off. But if you don't, and want to take advantage of all jQuery goodness, then use it.
jQuery's Sizzle selector engine can use querySelectorAll if it's available. It also smooths out inconsistencies between browsers to achieve uniform results. If you don't want to use all of jQuery, you could just use Sizzle separately. This is a pretty fundamental wheel to invent.
Here's some cherry-pickings from the source that show the kind of things jQuery(w/ Sizzle) sorts out for you:
Safari quirks mode:
if ( document.querySelectorAll ) {
(function(){
var oldSizzle = Sizzle,
div = document.createElement("div"),
id = "__sizzle__";
div.innerHTML = "<p class='TEST'></p>";
// Safari can't handle uppercase or unicode characters when
// in quirks mode.
if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
return;
}
If that guard fails it uses it's a version of Sizzle that isn't enhanced with querySelectorAll. Further down there are specific handles for inconsistencies in IE, Opera, and the Blackberry browser.
// Check parentNode to catch when Blackberry 4.6 returns
// nodes that are no longer in the document #6963
if ( elem && elem.parentNode ) {
// Handle the case where IE and Opera return items
// by name instead of ID
if ( elem.id === match[3] ) {
return makeArray( [ elem ], extra );
}
} else {
return makeArray( [], extra );
}
And if all else fails it will return the result of oldSizzle(query, context, extra, seed).
In terms of code maintainability, there are several reasons to stick with a widely used library.
One of the main ones is that they are well documented, and have communities such as ... say ... stackexchange, where help with the libraries can be found. With a custom coded library, you have the source code, and maybe a how-to document, unless the coder(s) spent more time documenting the code than writing it, which is vanishingly rare.
Writing your own library might work for you , but the intern sitting at the next desk may have an easier time getting up to speed with something like jQuery.
Call it network effect if you like. This isn't to say that the code will be superior in jQuery; just that the concise nature of the code makes it easier to grasp the overall structure for programmers of all skill levels, if only because there's more functional code visible at once in the file you are viewing. In this sense, 5 lines of code is better than 10.
To sum up, I see the main benefits of jQuery as being concise code, and ubiquity.
Here's a comparison if I want to apply the same attribute, e.g. hide all elements of class "my-class". This is one reason to use jQuery.
jQuery:
$('.my-class').hide();
JavaScript:
var cls = document.querySelectorAll('.my-class');
for (var i = 0; i < cls.length; i++) {
cls[i].style.display = 'none';
}
With jQuery already so popular, they should have made document.querySelector() behave just like $(). Instead, document.querySelector() only selects the first matching element which makes it only halfway useful.
Old question, but half a decade later, it’s worth revisiting. Here I am only discussing the selector aspect of jQuery.
document.querySelector[All] is supported by all current browsers, down to IE8, so compatibility is no longer an issue. I have also found no performance issues to speak of (it was supposed to be slower than document.getElementById, but my own testing suggests that it’s slightly faster).
Therefore when it comes to manipulating an element directly, it is to be preferred over jQuery.
For example:
var element=document.querySelector('h1');
element.innerHTML='Hello';
is vastly superior to:
var $element=$('h1');
$element.html('hello');
In order to do anything at all, jQuery has to run through a hundred lines of code (I once traced through code such as the above to see what jQuery was actually doing with it). This is clearly a waste of everyone’s time.
The other significant cost of jQuery is the fact that it wraps everything inside a new jQuery object. This overhead is particularly wasteful if you need to unwrap the object again or to use one of the object methods to deal with properties which are already exposed on the original element.
Where jQuery has an advantage, however, is in how it handles collections. If the requirement is to set properties of multiple elements, jQuery has a built-in each method which allows something like this:
var $elements=$('h2'); // multiple elements
$elements.html('hello');
To do so with Vanilla JavaScript would require something like this:
var elements=document.querySelectorAll('h2');
elements.forEach(function(e) {
e.innerHTML='Hello';
});
which some find daunting.
jQuery selectors are also slightly different, but modern browsers (excluding IE8) won’t get much benefit.
As a rule, I caution against using jQuery for new projects:
jQuery is an external library adding to the overhead of the project, and to your dependency on third parties.
jQuery function is very expensive, processing-wise.
jQuery imposes a methodology which needs to be learned and may compete with other aspects of your code.
jQuery is slow to expose new features in JavaScript.
If none of the above matters, then do what you will. However, jQuery is no longer as important to cross-platform development as it used to be, as modern JavaScript and CSS go a lot further than they used to.
This makes no mention of other features of jQuery. However, I think that they, too, need a closer look.
as the official site says:
"jQuery: The Write Less, Do More, JavaScript Library"
try to translate the following jQuery code without any library
$("p.neat").addClass("ohmy").show("slow");
I think the true answer is that jQuery was developed long before querySelector/querySelectorAll became available in all major browsers.
Initial release of jQuery was in 2006. In fact, even jQuery was not the first which implemented CSS selectors.
IE was the last browser to implement querySelector/querySelectorAll. Its 8th version was released in 2009.
So now, DOM elements selectors is not the strongest point of jQuery anymore. However, it still has a lot of goodies up its sleeve, like shortcuts to change element's css and html content, animations, events binding, ajax.
$("#id") vs document.querySelectorAll("#id")
The deal is with the $() function it makes an array and then breaks it up for you but with document.querySelectorAll() it makes an array and you have to break it up.
Just a comment on this, when using material design lite, jquery selector does not return the property for material design for some reason.
For:
<div class="logonfield mdl-textfield mdl-js-textfield mdl-textfield--floating-label">
<input class="mdl-textfield__input" type="text" id="myinputfield" required>
<label class="mdl-textfield__label" for="myinputfield">Enter something..</label>
</div>
This works:
document.querySelector('#myinputfield').parentNode.MaterialTextfield.change();
This does not:
$('#myinputfield').parentNode.MaterialTextfield.change();

jQuery performance - select by data-attr or by class?

Which is faster and why? Selecting div (for plugin needs) by $('div[data-something]') or $('div.something')? I lean towards the former since it's "cleaner".
Based on this SO question I know I shouldn't be using both. However I didn't find out whether there is a difference between these.
In Chrome 16 at least, there is no difference. However, if you make the class selector less specific ($(".test") for example), it does outperform the other methods:
That was somewhat unexpected, because as ShankarSangoli mentions, I thought the div.test class selector would be faster.
It will vary by browser. Nearly all browsers now support querySelectorAll, and jQuery will use it when it can. querySelectorAll can be used with attribute presence selectors, so if it's there jQuery doesn't have to do the work, it can offload it to the engine.
For older browsers without querySelectorAll, jQuery will obviously have to do more work, but even IE8 has it.
As with most of these things, your best bet is:
Don't worry about it until/unless you see a problem, and
If you see a problem, profile it on the browsers you intend to support and then make an informed decision.
Selecting by class is always faster than attribute selector because jQuery tries to use the native getElementByCalssName first if supported by browsers. If not it uses the querySelector which uses css selectors to find the elements within the page.

How do I select class within a class or a tag using Javascript getElementsByClass() function?

In jQuery it would simply be
$("a.class").randommethod();
or
$(".class1 .class2").randommethod();
How do I achieve the same effect using pure Javascript? (I'm editing a open-source software for personal use and it doesn't use jQuery)
You can't do it using getElementsByClassName. You would need to use something more like querySelectorAll, which accepts CSS style selectors.
var result = document.querySelectorAll('.class1 .class2');
You should note that neither method has full cross-browser support. That's why people use javascript libraries. If you don't need to support older browsers, then querySelectorAll is a good choice.
Another option is to use the Sizzle selector engine that jQuery uses.
You'll need to write your own selector engine, or use an established one such as sizzle (http://sizzlejs.com/), which is used by jQuery.

Categories