How to optimize $.find().first()? - javascript

I need to retrieve the first element.
I do that with this code...
$(element).find('.x').first();
As much as I understand, that code...
Retrieves all elements from element that matched .x,
Removes unneeded elements;
Is there any better way to do it? Like $.findOne() or something?

As per jQuery docs:
Because :first is a jQuery extension and not part of the CSS
specification, queries using :first cannot take advantage of the
performance boost provided by the native DOM querySelectorAll()
method. To achieve the best performance when using :first to select
elements, first select the elements using a pure CSS selector, then
use .filter(":first").
So rewriting your selector to:
$(element).find('.x').filter(":first")
or (this one will give you direct descendants only and will be faster than .find, unless you're looking for nested elements too)
$(element).children('.x').filter(":first")
should give you better results.
Update After valuable inputs from kingjiv and patrick dw (see comments),
it does seem that these two are faster than .filter(':first') contrary to what the doc claims.
$(element).find('.x').first(); // faster
$($(element).find('.x')[0]); // fastest

If you want to have it real fast, you should use native browsers methods. Modern browsers support querySelector [docs]:
var $result;
if(element.querySelector) {
$result = $(element.querySelector('.x'));
}
else {
$result = $(element).find('.x').first();
}
The usage is a bit limited, as it would only work if element is a single element and if the selector is a valid CSS selector. You could make a plugin out of it. But then, if you consider all cases, like multiple elements etc., there is probably no advantage anymore.
So again, if you have a very specific use case, this might be useful, if not, stick with jQuery.
Update: Turns out, making a plugin is still faster: jsPerf benchmark
(function($) {
$.fn.findOne = function(selector) {
try {
var element, i = 0, l = this.length;
while(i < l && (element = this[i].querySelector(selector)) === null) {
i++;
}
return $(element);
}
catch(e) {
return this.find(selector).first();
}
};
}(jQuery));
How this works:
The plugin iterates over the selected DOM elements and calls querySelector on each of them. Once an element is found, the loop will terminate and return the found element. There are two reasons an exception could occur:
The browsers does not support querySelector
The selector is not a pure CSS selector
In both cases the plugin will fall back to use the normal jQuery method.

As crazy as it seems, in every performance test I've seen, .first() has better performance than :first.
As most people are suggesting, it seems as though using $(element).find(".x:first") should have better performance. However, in reality .first is faster. I have not looked into the internals of jquery to figure out why.
http://jsperf.com/jquery-select-first
And apparently using [0] and then rewrapping in a jquery object is the fastest:
$($(element).find(".x")[0])
EDIT: See mrchief's answer for an explanation of why. Apparently they have now added it to the documentation.

This should be better
$(element).find('.x:first');

Use :first selector:
$(element).find('.x:first')

It's better to write:
$('a:first');
What you're writing is "in 'element', find '.x' and return the first one". And that can be expressed like this
$('.x:first', element);

how about using first-child pseudo class ? like
$(element).find('.x:first-child')
However it might generate issues if your structure is like
<div>
<p></p>
</div>
<div>
<p></p>
</div>
so actually it is not what you are looking for (if you mean general solution). Others mnetions :first and this seems to be the correct approach

Your bottleneck is really the .find(), which searches all the descendants instead of just the immediate children.
On top of that, you're searching for a class .x (which uses a jQuery custom search) instead of an ID or a tagname (which use native DOM methods).
I would use Mrchief's answer and then, if possible, fix those two bottlenecks to speed up your selector.

You could combine the $(element) and .find() calls using a descendant selector; I'm unsure of the performance comparison:
$("#element .x").first().hide();

That way is fine according to the jQuery documentation, or at least better than using :first selector.
You can try as alternatives .filter(":first") or get the first element using array accessor against the .find() result [0].
Also, instead of .find() you can change it to:
$('.x', element)
To narrow the search to .x elements inside element, intead of searching the whole document.

Related

jQuery selector for finding the first element after a given element that matches a selector

Let's say I have this HTML:
<textarea>blah</textarea>
<br>
<div class="select_this">hello!</div>
How can I select the DIV with class "select_this" when I already have the textarea identified? I don't want to use a class selector on the entire document because I'm working with a large document and class lookups are slow in older browsers.
jQuery .next() doesn't seem to do the trick, closest() only looks up the DOM tree, and .nextUntil() qualifies on everything I need except for the "select_this" div. Any other options out there?
There are two ways to do it.
Use this if you only have a few siblings:
$('textarea').nextAll('div.select_this').first();
The downside of this is that it test every subsequent element to see if it matches the selector, even after it's found the first one. Use this if you have many, many siblings, to save on evaluation:
$('textarea').nextUntil('div.select_this').andSelf().last().next();
Note also that it's better to use the first and last methods, rather than their corresponding selectors (:first, :last), because browsers don't natively understand the selectors, which slows the expression down considerably.
Edited to incorporate andSelf per comment below.
You want nextAll:
jQuery(yourTextarea).nextAll('.select_this:first');

jQuery selector speed

Is selecting by ID-only (or a single identifier) faster than when adding additional identifiers?
For example
$('#element')
vs
$('#container #element')
or even more specific:
$('body div#container div#element')
?
Yes, selecting by ID only should be the fastest, because jQuery (or Sizzle) can directly use getElementById. Otherwise the rest of the selector has to be evaluated as well, right to left.
$('#element') should be fastest, followed by $('div'). These map to the native functions document.getElementById and document.getElementsByTagName. Anything more complex has to go through complex scripting and document searching.
On everything but IE6, 7, and 8, $('.class') also map to the new document.getElementsByClassName function as well, but this is slower than the other two and still has to go through Sizzle if the browser doesn't support it.
You should always try to use as few selectors as you can that will correctly identify the element(s) that you wish to process. For instance if element is a unique id (as it should be), then #element will uniquely specify it and anything else will be wasteful, both in parsing and processing overhead. (This goes equally for CSS style rules, of course, although in this case the optimal choice of selectors may be different than when using jQuery.)
Actually calling
document.getElementById("element");
is fastest.
If you really want a jQuery object then call $(document.getElementById("element"));
Benchmark

Performance in jQuery with selectors

i was wondering things...
If i need to get the content or append an click function to an div, as the structure of the selectors it's something like that:
$('body #content #sidebar .modalwindow #global-content')
i want to target #global-content, the final id of the selectors.
what its better?
Just target it as $('#global-content') and do what i wanna or give to it all the path?
$('#global-content') is the best selector to use, altough maybe the whole selector will be executed the same way (if jQuery starts from right to left, which I'm not sure it does). ID should be unique and getElementById() is the fastest native browser method, so $('#global-content') is the fastest possible selector.
Keep in mind also, that when you are searching for something exactly 1 level lower in the DOM tree, you can put > in the selector. Example:
$('body .content') is equialent to $('body').find('.content')
$('body > .content') is equialent to $('body').children('.content')
The second one is faster.
You can experiment and try out your selectors here
a similar question was asked in
jQuery Selectors, efficiency
the answer is that
$('#global-content')
is faster
if you know the id of your element and if your id is really unique (as it should be). It is faster to call directly the id >> $('#global-content').
Thus, it is interpreted by jquery to one of the fastest selector getElementById() instead of filtering the DOM.
Note: I know jquery 1.5 and higher (maybe even since 1.4) were optimized to select by id even if the jquery code was adding too much information but that's not the best way to rely on the framework to correct a bad coding

jQuery Selectors, efficiency

I have been reading more lately about the efficiency of the different selector engines. I know that jQuery uses the Sizzle engine and this blog post about some jQuery stuff mentioned that the Sizzle engine will break apart your selector into an array then parse left to right.
It then, from right to left, begins deciphering each item with regular expressions. What this also means is that the right-most part of your selector should be as specific as possible — for instance, an id or tag name.
My question is whether it is more efficient to run a selector with just the ID specified or the tag name as well:
var div = $('#someId');
//OR
var div = $('div#someId');
Since I write my CSS in the div#someId form I tend to do my selectors the same way, am I causing Sizzle to perform extra work (assuming QuerySelectorAll is unavailable)?
jQuery and Sizzle optimize the #id selector [source] to document.getElementById(id). I think they aren't able to optimize it like this with the tag#id.
The first is faster.
BTW specifying the tag name for an #id selector is over-specifying, as there can be only one tag with a given id on the document. Over-specifying is slower even in CSS.
Rather than speculating, let's measure it!
Here's a test case with this page loaded, then matching a random element with both methods.
Make sure you scroll right down to the bottom.
http://jsperf.com/which-jquery-sizzle-selector-is-faster#runner
As you might expect, a plain id is faster than a tag qualified one (reduction to getElementByID). This is the same when using classes.
Selecting by ID is massively faster than selecting by class, mainly as IDs are guaranteed to be unique.
If you are using jQuery, you can assume a browser with getElementById. $('#someId') can be converted to document.getElementById('someId'). $('div#someId') won't be, so it will be faster to lose the tag name.
jsPerf demonstrating this. The difference is enormous.
var div = $('#someId'); //should be faster
jQuery will use getElementById() for the above selector
var div = $('div#someId'); //would probably preform slower due to finding all the divs first
jQuery will use getElementsByTagName(), then iterate though the array of elements for the above selector
You should also remember, tag names should definately be used with class selectors (whenever possible)
var div = $('div.myclass') //faster than the statement below
versus
var div = $('.myclass') //slower
JsPerf: http://jsperf.com/jquery-id-vs-tagname-id
The first one is going to be faster because it only has to check the id. The second one runs the same check AND has to make sure the tagname is correct. div#id won't give you the element with id id unless it is a div
You can see from the source code here: http://code.jquery.com/jquery-1.6.2.js in the function init.
The fastest selector is $('') which just returns an empty jQuery object immediately.
$('body') is next, which jQuery converts to document.body
The next is $('#id') which uses document.getElementById('id').
Any other selector such as $('div#id') will just become a call to $(document).find('div#id'). find() is very complex compared to any of those other solutions and uses Sizzle JS to select the div.

jquery - which DOM selection method is better to use

Which is better to use and why?
if ($(target).parents('div#test').length) {
or
var target = $(evt.target);
if (target.parents('div#test').length){
There are preformance gains to be had in using the second option. If you are going to reuse the selector multiple times.
Essentially you are caching your DOM traversal if you use the same selector multiple times.
See this answer for more details

Categories

Resources