(Side note: This post was published before on this blog, but since then I lost the database in a hosting issue, so this is rewritten. So if you think you recognise some of this, you may well do!)
While jQuery is a very popular library and does things very well, there are always improvements we can make. Such improvements on a small project may seem trivial, but to quote a popular supermarket, “every little helps”. So in this tutorial I’ll show you how we can improve and speed up how we select elements with jQuery.
Using jQuery you can select elements using many methods, the post popular usage of selections is usually via an Id, a tag or a class:
$("#myElem"); //select using id
$(".myElem"); //select using class
$("a"); //select using tag
Native Javascript has a built in DOM method for selecting by Id or Tag, but not one for selecting elements by class. So, when you select an element via an Id, jQuery goes off and uses document.getElementById(), and similarly document.getElementsByTagName() for tag names. However, with there being no native class selector, jQuery has to do a lot more work (often looping through the entire DOM) to find the correct element(s). So therefore, whenever you can, you should avoid selecting by Class.
If there comes a time when you simply must select elements through a class selector, the last you can do for poor old jQuery is provide a context. This is often an overlooked yet very useful feature. By providing a context to jQuery, when it looks for elements by their class, it will only search within the context you provide.
UPDATE: A comment by Adam and also by Owen pointed out that this actually makes jQuery do more work. Some better solutions are to do this:
$("div.myElem"); //here jQuery can use getElementsByTagName() first to narrow down the search.
Or, if earlier on in your code you had cached a selector, this is also a good way:
$(".myElem", element); //where element has been cached already.
Thanks to Owen and Adam for making me aware of this. If you read Adam’s comment below, he also shows some benchmarking tests he did to back up his comment.
If you can, avoid going back up to parent level. For example, the other day I saw this:
$("elem").find("p").css("display", "none").parent().find("h2").css("display", "none");
This is pretty poor. I asked why the code was done as such, and it turns out the user never knew that the .siblings() function could take a selector, meaning the code could be cut down:
$("elem").find("p").css("display", "none").siblings("h2").css("display", "none")
But this can still be improved:
$("elem").children("p, h2").css("display", "none");
Look at how much shorter that code is! By giving jQuery’s children() function two selectors, we cut down on how much work jQuery has to do. In the previous example, we selected the element, then found the paragraph, then changed the CSS of that, then searched for the h2 sibling, then changed the CSS of that! Now all we do is select our element, find the specific children, and apply our CSS change to both those elements at once. Much nicer, I think you will agree.
If you’ve selected an element you know you are going to have to refer to lots, save it! For example, this is pretty poor, jQuery will get upset if you do this:
$("#myElem").empty()
$("#myElem").css("border", "1px solid blue");
There are two better ways to do this. The first is to chain:
$("#myElem").empty().css("border", "1px solid blue");
And the second is to cache the selector:
var element = $("#myElem");
element.empty();
element.css("border", "1px solid blue")
I tend to save the element to a variable if I will need to use it later in the function. However, if I’m doing multiple things to an element at the same time, I just chain.
Hint – I’ve got into the habit of appending all variables that store the jQuery object with a dollar sign ($) to differentiate between those and normal variables. Like so:
var $myelement = $("#myelement");
var anumber = 5 * 5;
Now I can immediately see that $myelement relates to a jQuery selector, and anumber does not.
Caching also applies to the “this” keyword. Consider this loop:
$("div").each(function(i) {
$(this).addClass("myClass");
if($(this).hasClass("newClass") {
$(this).addClass("anotherClass");
}
});
While this might look all cosy, look how many times jQuery has to select the current element using $(this). This loop is much better:
$("div").each(function(i) {
var $this = $(this);
$this.addClass("myClass");
if($this.hasClass("newClass") {
$this.addClass("anotherClass");
}
});
Rarely used as much as it should, andSelf() is useful for chaining the previous selection. For example, take code such as this:
$("div").find("p").addClass("myClass").parent().addClass("myClass");
That would seem the only logical way to do things. But no! Check this out:
$("div").find("p").andSelf().addClass("myClass");
Which again, saves us repeating the addClass() function and generally is nicer to look at.
So that’s that, some easy ways to stripe down time your javascript takes to execute and generally make it nicer, cleaner, more DRY (Don’t repeat Yourself). Don’t you just love jQuery? Thanks for reading.
14 Responses
tweetassassin (Arnie Stubbs)
28|Aug|2009Clever jQuery Selectors by I Speak Web Stuff :: Blog of Jack Franklin http://tinyurl.com/mqs9f7
Grant Z
28|Aug|2009This is very helpful! Thank you for explaining so clearly.
Kevin
28|Aug|2009Very useful post. Bookmarked for future jQuery reference.
Twitted by jbasilio
28|Aug|2009[...] This post was Twitted by jbasilio [...]
Owen Gerrard
28|Aug|2009I’m curious about this: $(”.myElems”, $(”#myID”)); Would $(”#myID .myElems”); work the same and be only instantiating jQuery once?
Jack F
28|Aug|2009Hi Owen, it would see so but I’m afraid not. When you use jQuery like you suggested:
$(”#myID .myElems”)
jQuery actually searches from the very right. So first it finds all elements with a class of “myElems” and the narrows it down to those within an element of “myID”.
Thanks everyone for all your comments so far.
adam sontag
28|Aug|2009Hey, I am pretty sure that reccomendation to “always provide a context”, especially when that context is the re-execution of a domquery, is completely inaccurate. While providing a context is very wise in general, perhaps if you have selected the elements earlier on, the method you suggested is particularly burdensome.
You can see this in effect in this screencap of me benchmarking the various selection techniques to get all div.category within #bgcontain on this very page.
http://gyazo.com/b7b48e884a3f42164faf301e2ea8d82f.png
$(”.categories”,$(”#bgcontain”)) takes almost twice as long over 1000 iterations as $(”#bgcontain .categories”);
A better tip is to always use element in tandem with class for class searches, ie, $(”div.categories”), as it allows jQuery to perform a getElementsByTagName search first.
Jack F
28|Aug|2009Hi Adam,
Thanks for commenting. I can see what you mean and the benchmarks are very surprising indeed. I think you are correct in saying that this:
$(”#MyElem”, foo) where foo is an already cached selector is best, but as Owen suggested (and I wrongly dismissed) $(”#myElem”, $(”div”)) is completely the wrong way to go about things. Many thanks for pointing that out to me, and I will update the post.
Owen Gerrard
28|Aug|2009Cool.
I wonder if it might it be worth noting that you could also write: $(”elem”).find(”p, h2″).css(”display”, “none”); as opposed to $(”elem”).children(”p, h2″).css(”display”, “none”); in a scenario where you may be searching deeper than the immediate children, but that using children() is faster than find() in this case?
Jack F
28|Aug|2009Hi Owen,
This link:
http://blog.ekini.net/2009/03/16/jquery-children-vs-find-which-is-faster/
Pretty much confirms what I would suspect. Children() only traverses the immediate children, whereas find() does a lot more work. So use Children() if you are only interested in the children, but find if you want deeper level elements.
On that note, I wonder if myElem.children().children(”h2″) is quicker than myElem.find(”h2″) (where the h2 is a grandchild of myElem).
Clever jQuery Selectors « I Speak Web Stuff :: Blog of Jack Franklin
30|Aug|2009[...] Continued here: Clever jQuery Selectors « I Speak Web Stuff :: Blog of Jack Franklin [...]
XHTMLFactory (XHTMLFactory)
30|Aug|2009Clever jQuery Selectors http://bit.ly/R62tX
Ultimate collection of top jQuery tutorials, tips-tricks and techniques to improve performance « Technosiastic!
24|Sep|2009[...] Clever jQuery Selectors [...]
Shahriar Hyder
24|Sep|2009Very clever jQuery selectors indeed mate. I have also linked to yours from my blog post below where I am trying to collect the most useful and common jQuery code snippets for JavaScript over the web. Here is the title and the link to the jQuery link compilation endeavor:
Ultimate collection of top jQuery tutorials, tips-tricks and techniques to improve performance
http://technosiastic.wordpress.com/2009/09/24/collection-of-top-jquery-tutorials-tips-tricks-techniques-to-improve-performance/
Leave a reply
Search
Recent Postage
I Love Comments
Blogroll
A design creation of Design Disease
Copyright © 2007 - I Speak Web Stuff :: Blog of Jack Franklin - is proudly powered by WordPress
InSense 1.0 Theme by Design Disease brought to you by HostGator Web Hosting.