jQuery Optimization/Best Practices - javascript

Ok saddle up cowboys, because this is going to be a long one. I have been spending the morning going through some of my old code and I'm left wondering about best practices and optimzation. In order to avoid a ride down subjective lane I'll just post some examples with some hopefully easy to answer questions. I will try to keep the examples very simple for ease of an answer and to decrease the likelihood of mistakes. Here we go:
1) Assignment vs jQuery Calls
I understand that when accessing selectors it's generally considered better to assign a selector to a variable rather than make the same call more than once - ex.
$('div#apples').hide();
$('div#apples').show();
vs.
var oranges = $('div#oranges');
oranges.show();
oranges.hide();
Does this same rule apply when referencing jQuery's $(this)? Ex. A simple bit of script to make some data in a table clickable and customize the link.
$('tr td').each( function() {
var colNum = $(this).index();
var rowNum = $(this).parent().index();
$(this).wrap('<a href="example.com/hello.html?column=' + colNum + '&row=' + rowNum +'">');
})
vs.
$('tr td').each( function() {
var self = $(this);
var colNum = self.index()
var rowNum = self.parent().index()
self.wrap('<a href="example.com/hello.html?column=' + colNum + '&row=' + rowNum +'">');
});
2) this vs $(this)
Ok so this next one is something that I have wondered about for a long time but I can't seem to find any information on it. Please excuse my ignorance. When does it make sense to call the vanilla js this as opposed to the jQuery wrapped $(this)? It's my understanding that -
$('button').click(function() {
alert('Button clicked: ' + $(this).attr('id'));
});
Is much less efficient than accessing the DOM attribute of the vanilla this object like the following -
$('button').click(function() {
alert('Button clicked: ' + this.id);
});
I understand what is going on there, Im just wondering if there is a rule of thumb to follow when deciding which to use.
3) Is more specificity always better?
This one is pretty simple, is it ALWAYS beneficial to be more specific with our selectors? It's easy to see that $('.rowStripeClass') would be much slower than $('#tableDiv.rowStripeClass'), but where do we draw the line? Is $('body div#tableDiv table tbody tr.rowStripeClass') faster still? Any input would be appreciated!
If you've made it this far, thanks for taking a look! If you haven't, :p
​

I'll try to answer these as concisely as possible:
Cache it when it's used often, especially in a loop situation, running the same code to get the same result is never a good thing for performance, cache it.
Use this when you only need a DOM element and $(this) when you need the jQuery methods (that wouldn't be available otherwise), your example of this.id vs $(this).attr("id") is perfect, some more common examples:
Use this.checked instead of $(this).is(':checked')
Use $.data(this, 'thing') instead of $(this).data('thing')
Any other case where creating a jQuery object isn't useful basically.
Decending from an ID selector is preferred for performance...how specific do you need to be? That completely depends, in short: be as specific as you need to be.

1) Assignment vs jQuery Calls
Does this same rule apply when referencing jQuery's $(this)?
Yes, absolutely. A call to the $ function creates a new jQuery object and with it comes associated overhead. Multiple calls to $ with the same selector will create a new object every time.
2) this vs $(this)
I would say knowing the difference is important because at times it becomes crucial that you don't wrap your objects with jQuery. In most cases, you wouldn't want to do premature optimization and just to keep things consistent, always wrap them with $(this), and preferably cache it in a variable. However, consider this extreme example of an unordered list <ul> that contains a million <li> elements:
$("#someList li").each(function() {
var id = $(this).attr('id');
});
A million new objects will be created which will incur a significant performance penalty, when you could have done without creating any new objects at all. For attributes and properties that are consistent across all browsers, you could access them directly without wrapping it in jQuery. However, if doing so, try to limit it to cases where lots of elements are being dealt with.
3) Is more specificity always better?
Not always. It mostly depends on browsers, and again not worth delving into micro-optimizations unless you know for sure that something is running rather slow in your application. For example:
$("#someElement") vs $("#someElement", "#elementsContainer")
It may appear that since we are also provide a context when searching an element by id, that the second query is going to be faster, but it's the opposite. The first query translates to a direct call to the native getElementById(..) while the second one doesn't because of the context selector.
Also, some browsers might provide an interface to access elements by class name using getElementsByClassName and jQuery might be using it for those browsers for faster results, in which case providing a more specific selector such as:
$("#someElement.theClass")
might actually be a hindrance than simply writing:
$(".theClass")

This blog isn't too dated, but it supplies some answers to your questions as well as gives some more info on speeding up your site when using jquery: http://www.artzstudio.com/2009/04/jquery-performance-rules/
One of my favorites is number six which states to limit DOM manipulation. It's always a bad thing to do a .append in a for loop since each time you are appending to the DOM, which is an expensive operation.

Up to your questions:
Caching the jQuery object should yield best performance. It will avoid DOM lookups which is what can get slow when performed many times. You can benefit from jQuery chaining - sometimes there is no need for a local variable.
The same goes with $(this) when this is a DOM element. Despite the fact that this is the fastest way to obtain a jQuery object it is still slower than caching. If the vanilla DOM element would suffice - then don't call jQuery at all. The example with the id attribute is excellent - prefer this.id than $(this).attr('id) if you are not going to need $(this)
More specific selectors will decrease the DOM lookup time indeed. However there is indeed a line to be drawn - make the selectors more specific only if you are 100% sure this would improve performance in a noticeable way.

The only situations you should keep your eye on are loops and events. Because every action you make in one of these will be done in every iteration or on every event.
Assignment vs jQuery Calls
Your example is not the best. The place where you should save references to jQuery objects are the ones used in loops or events, or which are results of complex queries.
this vs $(this)
Again in performance critical situations raw dom is better. Other than that you should chose which is shorter or more readable. Surprise, surprise it's not always jQuery.
Is more specificity always better?
There are more types of specificity which are usually confused by people. One of them is useless which e.g.: a tag name for an id selector tag#id, it will be slower than a simple id. But there is another type when it will be a huge benefit to be specific.
Now this type depends on the browser, because the modern ones will sacrifice for the old ones, but it worths the trade-off This happens when you specify a tag for a class tag.class. In IE 6-7 it will be significantly faster than a simple .class, because sizzle can make use of the fast document.getElementsByTagName function. Now another type is when you specify too much ancestors. This will slow things down in every browser. This is because the selector is executed from right to left. The rule to keep in mind: always be the rightmost selector as specific as possible.

2013 blog article about the best jQuery practices
Updated answers on your question and even more regarding the best jQuery practices to apply nowadays, this article is dealing with interesting subjects that are really helpful and that you might want to read.
It deals with the subjects asked here and even more: the animate function,jQuery promises, best ways to import jQuery, jQuery events etc.
Hope that will be helpful to you!

Related

Should I be caching jQuery selectors in the global namespace? [duplicate]

I have some trouble that comes from my Javascript (JS) codes, since I sometimes need to access the same DOM elements more than once in the same function. Some reasoning is also provided here.
From the point of view of the performance, is it better to create a jQuery object once and then cache it or is it better to create the same jQuery object at will?
Example:
function(){
$('selector XXX').doSomething(); //first call
$('selector XXX').doSomething(); //second call
...
$('selector XXX').doSomething(); // n-th call
}
or
function(){
var obj = $('selector XXX');
obj.doSomething(); //first call
obj.doSomething(); //second call
...
obj.doSomething(); // n-th call
}
I suppose that the answer probably depends by the value of "n", so assume that n is a "small" number (e.g. 3), then a medium number (e.g. 10) and finally a large one (e.g. 30, like if the object is used for comparison in a for cycle).
Thanks in advance.
It is always better to cache the element, if n is greater than 1, cache the element, or chain the operations together (you can do $('#something').something().somethingelse(); for most jQuery operations, since they usually return the wrapped set itself). As an aside, it has become a bit of a standard to name cache variables beginning with a money sign $ so that later in the code it is evident that you are performing an operation on a jQuery set. So you will see a lot of people do var $content = $('#content'); then $content.find('...'); later on.
The second is superior. Most importantly, it is cleaner. In the future, if you want to change your selector, you only need to change it one place. Else you need to change it in N places.
Secondly, it should perform better, although a user would only notice for particularly heavy dom, or if you were invoking that function a lot.
If you look at this question from a different perspective, the correct answer is obvious.
In the first case, you're duplicating the selection logic in every place it appears. If you change the name of the element, you have to change each occurence. This should be reason enough to not do it. Now you have two options - either you cache the element's selector or the element itself. Using the element as an object makes more sense than using the name.
Performance-wise, I think the effect is negligible. Probably you'll be able to find test results for this particular use-case: caching jQuery objects vs always re-selecting them. Performance might become an issue if you have a large DOM and do a lot of lookups, but you need to see for yourself if that's the case.
If you want to see exactly how much memory your objects are taking up, you can use the Chrome Heap Profiler and check there. I don't know if similar tools are available for other browsers and probably the implementations will vary wildly in performance, especially in IE's case, but it may satisfy your curiosity.
IMO, you should use the second variant, storing the result of the selection in an object, no so much as to improve performance but to have as little duplicate logic as possible.
As for caching $(this), I agree with Nick Craver's answer. As he said there, you should also use chaining where possible - cleans up your code and solves your problem.
You should take a look at
http://www.artzstudio.com/2009/04/jquery-performance-rules/
or
http://addyosmani.com/jqprovenperformance/
I almost always prefer to cache the jQuery object but the benefit varies greatly based on exactly what you are using for your selector. If you are using ids then the benefit is far less than if you are using types of selectors. Also, not all selectors are created equally so try to keep that in mind when you write your selectors.
For example:
$('table tr td') is a very poor selector. Try to use context or .find() and it will make a BIG difference.
One thing I like to do is place timers in my code to see just how efficient it is.
var timer = new Date();
// code here
console.log('time to complete: ' + (new Date() - timer));
Most cached objects will be performed in less than 2 milliseconds where as brand new selectors take quite a bit longer because you first have to find the element, and then perform the operation.
In JavaScript, functions are generally short-lived—especially when hosted by a browser. However, a function’s scope might outlive the function. This happens, for example, when you create a closure. If you want to prevent a jQuery object from being referenced for a long time, you can assign null to any variables that reference it when you are done with that variable or use indirection to create your closures. For example:
var createHandler = function (someClosedOverValue) {
return function () {
doSomethingWith(someClosedOverValue);
};
}
var blah = function () {
var myObject = jQuery('blah');
// We want to enable the closure to access 'red' but not keep
// myObject alive, so use a special createHandler for it:
var myClosureWithoutAccessToMyObject = createHandler('red');
doSomethingElseWith(myObject, myClosureWithoutAccessToMyObject);
// After this function returns, and assuming doSomethingElseWith() does
// not itself generate additional references to myObject, myObject
// will no longer have any references and be elligible for garbage
// collection.
}
Because jQuery(selector) might end up having to run expensive algorithms or even walk the DOM tree a bit for complex expressions that can’t be handled by the browser directly, it is better to cache the returned object. Also, as others have mentioned, for code clarity, it is better to cache the returned object to avoid typing the selector multiple times. I.e., DRY code is often easier to maintain than WET code.
However, each jQuery object has some amount of overhead. So storing large arrays of jQuery objects in global variables is probably wasteful—unless if you actually need to operate on large numbers of these objects and still treat them as distinct. In such a situation, you might save memory by caching arrays of the DOM elements directly and using the jQuery(DOMElement) constructor which should basically be free when iterating over them.
Though, as people say, you can only know the best approach for your particular case by benchmarking different approaches. It is hard to predict reality even when theory seems sound ;-).

Caching of javascript variables [duplicate]

I have some trouble that comes from my Javascript (JS) codes, since I sometimes need to access the same DOM elements more than once in the same function. Some reasoning is also provided here.
From the point of view of the performance, is it better to create a jQuery object once and then cache it or is it better to create the same jQuery object at will?
Example:
function(){
$('selector XXX').doSomething(); //first call
$('selector XXX').doSomething(); //second call
...
$('selector XXX').doSomething(); // n-th call
}
or
function(){
var obj = $('selector XXX');
obj.doSomething(); //first call
obj.doSomething(); //second call
...
obj.doSomething(); // n-th call
}
I suppose that the answer probably depends by the value of "n", so assume that n is a "small" number (e.g. 3), then a medium number (e.g. 10) and finally a large one (e.g. 30, like if the object is used for comparison in a for cycle).
Thanks in advance.
It is always better to cache the element, if n is greater than 1, cache the element, or chain the operations together (you can do $('#something').something().somethingelse(); for most jQuery operations, since they usually return the wrapped set itself). As an aside, it has become a bit of a standard to name cache variables beginning with a money sign $ so that later in the code it is evident that you are performing an operation on a jQuery set. So you will see a lot of people do var $content = $('#content'); then $content.find('...'); later on.
The second is superior. Most importantly, it is cleaner. In the future, if you want to change your selector, you only need to change it one place. Else you need to change it in N places.
Secondly, it should perform better, although a user would only notice for particularly heavy dom, or if you were invoking that function a lot.
If you look at this question from a different perspective, the correct answer is obvious.
In the first case, you're duplicating the selection logic in every place it appears. If you change the name of the element, you have to change each occurence. This should be reason enough to not do it. Now you have two options - either you cache the element's selector or the element itself. Using the element as an object makes more sense than using the name.
Performance-wise, I think the effect is negligible. Probably you'll be able to find test results for this particular use-case: caching jQuery objects vs always re-selecting them. Performance might become an issue if you have a large DOM and do a lot of lookups, but you need to see for yourself if that's the case.
If you want to see exactly how much memory your objects are taking up, you can use the Chrome Heap Profiler and check there. I don't know if similar tools are available for other browsers and probably the implementations will vary wildly in performance, especially in IE's case, but it may satisfy your curiosity.
IMO, you should use the second variant, storing the result of the selection in an object, no so much as to improve performance but to have as little duplicate logic as possible.
As for caching $(this), I agree with Nick Craver's answer. As he said there, you should also use chaining where possible - cleans up your code and solves your problem.
You should take a look at
http://www.artzstudio.com/2009/04/jquery-performance-rules/
or
http://addyosmani.com/jqprovenperformance/
I almost always prefer to cache the jQuery object but the benefit varies greatly based on exactly what you are using for your selector. If you are using ids then the benefit is far less than if you are using types of selectors. Also, not all selectors are created equally so try to keep that in mind when you write your selectors.
For example:
$('table tr td') is a very poor selector. Try to use context or .find() and it will make a BIG difference.
One thing I like to do is place timers in my code to see just how efficient it is.
var timer = new Date();
// code here
console.log('time to complete: ' + (new Date() - timer));
Most cached objects will be performed in less than 2 milliseconds where as brand new selectors take quite a bit longer because you first have to find the element, and then perform the operation.
In JavaScript, functions are generally short-lived—especially when hosted by a browser. However, a function’s scope might outlive the function. This happens, for example, when you create a closure. If you want to prevent a jQuery object from being referenced for a long time, you can assign null to any variables that reference it when you are done with that variable or use indirection to create your closures. For example:
var createHandler = function (someClosedOverValue) {
return function () {
doSomethingWith(someClosedOverValue);
};
}
var blah = function () {
var myObject = jQuery('blah');
// We want to enable the closure to access 'red' but not keep
// myObject alive, so use a special createHandler for it:
var myClosureWithoutAccessToMyObject = createHandler('red');
doSomethingElseWith(myObject, myClosureWithoutAccessToMyObject);
// After this function returns, and assuming doSomethingElseWith() does
// not itself generate additional references to myObject, myObject
// will no longer have any references and be elligible for garbage
// collection.
}
Because jQuery(selector) might end up having to run expensive algorithms or even walk the DOM tree a bit for complex expressions that can’t be handled by the browser directly, it is better to cache the returned object. Also, as others have mentioned, for code clarity, it is better to cache the returned object to avoid typing the selector multiple times. I.e., DRY code is often easier to maintain than WET code.
However, each jQuery object has some amount of overhead. So storing large arrays of jQuery objects in global variables is probably wasteful—unless if you actually need to operate on large numbers of these objects and still treat them as distinct. In such a situation, you might save memory by caching arrays of the DOM elements directly and using the jQuery(DOMElement) constructor which should basically be free when iterating over them.
Though, as people say, you can only know the best approach for your particular case by benchmarking different approaches. It is hard to predict reality even when theory seems sound ;-).

$().each vs $.each vs for loop in jQuery?

I Can't understand why it is happening.
I read here that :
The first $.each constitutes a single function call to start the
iterator.
The second $(foo.vals).each makes three function calls to start the
iterator.
The first is to the $() which produces a new jQuery wrapper
set (Not sure how many other function calls are made during this
process).
Then the call to $().each.
And finally it makes the internal
call to jQuery.each to start the iterator.
In your example, the difference would be negligible to say the least.
However, in a nested use scenario, you might find performance becoming
an issue.
Finally, Cody Lindley in jQuery Enlightenment does not recommend using
$.each for iterations greater than 1000 because of the function calls
involved. Use a normal for( var i = 0... loop.
So I tested it with this jsperf :
(task : find Tr's who has checked checkbox inside of them , and color that tr.)
This is the jsbin
But look at jsperf
against all expectations , the opposite is the true. ( chrome and FF and IE)
The one who uses $().each ( which calls three methods is the fastest
and etc..
What is going on here?
Your test is too heavy to really determine the actual difference between the three looping options.
If you want to test looping, then you need to do your best to remove as much non-related work from the test as possible.
As it stands, your test includes:
DOM selection
DOM traversal
element mutation
All of those are quite expensive operations compared to the loops themselves. When removing the extra stuff, the difference between the loops is much more visible.
http://jsperf.com/asdasda223/4
In both Firefox and Chrome, the for loop is well over 100x faster than the others.
Well
$.each() is a jQuery function being executed which will be used to iterate over your list, so the overhead should be the jQuery function as well as the overhead of calling for that function for every item in the list. In this case
$(thing).each() The idea behind this is that the $(thing) makes an jQuery instance and then you iterate over this instance (.each acts on that instance). In your case, because the instance you called it with is already a jQuery object, the overhead is minimal (are you an instance, oh yes you are).
for() In this case there is no overhead at all, except looking up the length of the list on each iteration.
Consider doing:
var l = g.length;
for (var i=0;i<l;i++) {
// code;
}
Depending on your HTML most of the time could very well be in the Sizzle Jquery parser finding your selector in the document.
Also note, I don't think your selector is the best, unless things have changed significantly recently jQuery selectors are evaluated right to left, consider limiting the scope of the selector by doing a .find() on everything beneath the first tag referenced by id as it will then be searching only a subset of the document.
Different approach to your "task" http://jsfiddle.net/ADMnj/17/
But i guess the performance issues are coming from that you dont state selector the in the right matter
#t tr input:checkbox:checked
VS
#t tr :checkbox:checked
Tough the right way to check if a checkbox is checked would be to call it like this
#t tr input[checked="checked"]
W3.ORG's selector list see the E[foo]
And last but not least the fastest is also the one with the shortest code which might be the slight performance different you get from 3 lines vs 4 and 5 lines of code but cant prove this fact

what is the difference between $("#context .searched") and $(".searched",$("#context"))?

I had that question in mind for a long time.
Theoretically, jQuery core function accepts an optional value that can be a DOM element - $(".searched",$("#context")[0]) - or a jQuery object - $(".searched",$("#context") ) .
I discovered that last question reading that fine article.
But i really cant see the difference between use a context and pass a more complex css expression. If there is no difference in the way it works, is there any perfomance difference?
Thanks
It gets converted to a DOM element (in Sizzle, the context portion) to search in either of your cases, ultimately doing a .find() under the covers.
If you're concerned about performance (why not be as fast as possible?), you should use this instead:
$("#context .searched")
This version gets converted back into a jQuery object:
$("#context")[0]
So it's a bit slower on the jquery side, since it has to be wrapped in a jquery object before the .find() call, that performance difference is very minimal, but it's the only difference so I'm noting it :)
The major difference would be that $(".searched", context); can take a variable as a context as well. It is effectively doing $(context).find('.searched'); under the hood, and I think the second version is more readable anyway, so I usually use that.
The use for this situation would be something like this:
$.fn.highlightSearch = function() {
return this.each(function() {
$('.searched', this).addClass('highlighted');
// the commented line performs the same thing:
// $(this).find('.searched').addClass('highlighted');
});
};
$('#context').highlightSearch();
$('.somethingElse').highlightSearch();
Notice that in this case, you can't simply append the new selector on the end of the original.
If you have no other reason to hold a copy of $('#context'), then using $('#context .searched') is going to be quicker, and simpler. However, if you already had $('#context') stored in a variable, its better to use .find(select) or the $(selector, context) form to search for your contained elements.
Readability: a CSS selector like $("#context .searched") is far more readable than the other.

JQuery/JavaScript performance using $(this)

I find myself doing a lot of this kind of JQuery:
$('.filter-topic-id').each(function () {
var me = $(this);
if (me.text() == topics[k]) {
me.parent().show();
}
});
I store $(this) in a variable called me because I'm afraid it will re-evaluate $(this) for no reason. Are the major JavaScript engines smart enough to know that it doesn't have to re-evaluate it? Maybe even JQuery is smart enough somehow?
They are not smart enough to know not to revaluate $(this) again, if that's what your code says. Caching a jQuery object in a variable is a best practice.
If your question refers to your way in the question compared to this way
$('.filter-topic-id').each(function () {
if ($(this).text() == topics[k]) { // jQuery object created passing in this
$(this).parent().show(); // another jQuery object created passing in this
}
});
your way is the best practice.
Are the major JavaScript engines smart enough to know that it doesn't have to re-evaluate it?
No. But if you are using jQuery you are presumably aiming for readability rather than necessarily maximum performance.
Write whichever version you find easiest to read and maintain, and don't worry about micro-optimisations like this until your page is too slow and you've exhausted other more significant sources of delay. There is not a lot of work involved in calling $(node).
You could try to profile your code with Firebug and see if using $(this) many times slows your app or not
There is no good way that a javascript can determine that the following is true:-
fn(x) == fn(x);
Even if this was possible not calling the second fn could only be valid if it could be guaraneed that fn has not have other side-effects. When there is other code between calls to fn then its even more difficult.
Hence Javascript engines have no choice but to actually call fn each time it is invoked.
The overhead of calling $() is quite small but not insignificant. I would certainly hold the result in a local variable as you are doing.
this is just a reference to the current DOM element in the iteration, so there's little or no overhead involved when calling $(this). It just creates a jQuery wrapper around the DOM element.
I think you'll find that calling the jQuery function by passing a dom element is perhaps the least-intensive of ways to construct the object. It doesn't have to do any look-ups or query the DOM, just wrap it and return it.
That said, it definitely doesn't hurt to use the method you're using there, and that's what I do all the time myself. It certainly helps for when you create nested closures:
$('div').click(function() {
var $this = $(this);
$this.find("p").each(function() {
// here, there's no reference to the div other than by using $this
alert(this.nodeName); // "p"
});
});

Categories