jQuery best practices
Last week, I compiled “jQuery Design Ideas” .
That article is an introductory tutorial, explaining “how to use jQuery” from the perspective of design thinking . Today’s article goes one step further and explains “how to make good use of jQuery” .
I mainly refer to Addy Osmani’s PPT ” jQuery Proven Performance Tips And Tricks”. He is a member of the jQuery development team and has a certain degree of authority. His conclusions are supported by test data, which is very valuable.
=============================================
jQuery best practices
Ruan Yifeng finishing
1. Use the latest version of jQuery
The jQuery version is updated quickly, and you should always use the latest version. Because the new version will improve performance, there are many new features.
Let’s take a look at the difference in performance between different versions of jQuery. Here are the three most common jQuery selection statements:
$(‘.elem’)
$(‘.elem’, context)
context.find(‘.elem’)
We use the three versions of jQuery 1.4.2, 1.4.4, and 1.6.2 to test to see how many times the browser can execute in 1 second. The results are as follows:
It can be seen that the number of runs of version 1.6.2 far exceeds that of the two old versions. Especially for the first sentence, the performance has been improved several times.
The tests of other statements, such as .attr(“value”) and .val() , also perform better in the new version of jQuery than the old version.
2. Use the right selector
In jQuery, you can use multiple selectors to select the same web page element. The performance of each selector is different, and you should understand their performance differences.
(1) The fastest selector: id selector and element tag selector
For example, the following statement performs best:
$(‘#id’)
$(‘form’)
$(‘input’)
When encountering these selectors, jQuery will automatically call the browser’s native methods (such as getElementById()), so their execution speed is fast.
(2) The slower selector: class selector
The performance of $(‘.className’) depends on different browsers.
Firefox, Safari, Chrome, and Opera browsers all have a native method getElementByClassName(), so the speed is not slow. However, IE5-IE8 have not deployed this method, so this selector will be quite slow in IE.
(3) The slowest selector: pseudo-class selector and attribute selector
Let’s look at an example first. To find out all the hidden elements in the webpage, you need to use the pseudo-class selector:
$(‘:hidden’)
Examples of attribute selectors are:
$(‘[attribute=value]’)
These two statements are the slowest, because browsers have no native methods for them. However, some new versions of browsers have added querySelector() and querySelectorAll() methods, which will greatly improve the performance of this type of selector.
Finally, the performance comparison chart of different selectors .
As you can see, the ID selector is far ahead, followed by the label selector, and the third is the Class selector. Other selectors are very slow.
3. Understand the relationship between child elements and parent elements
The following six selectors select child elements from parent elements. Do you know which is the fastest and which is the slowest?
$(‘.child’, $parent)
$parent.find(‘.child’)
$parent.children(‘.child’)
$(‘#parent> .child’)
$(‘#parent .child’)
$(‘.child’, $(‘#parent’))
Let’s look at it sentence by sentence.
(1) $(‘.child’, $parent)
The meaning of this statement is, given a DOM object, and then select a child element from it. jQuery will automatically convert this statement to $.parent.find(‘child’), which will cause a certain performance loss. It is 5%-10% slower than the fastest form.
(2) $parent.find(‘.child’)
This is the fastest sentence. The .find() method will call the browser’s native methods (getElementById, getElementByName, getElementByTagName, etc.), so it is faster.
(3) $parent.children(‘.child’)
This statement is inside jQuery, using $.sibling() and javascript’s nextSibling() method to traverse the nodes one by one. It is about 50% slower than the fastest form.
(4) $(‘#parent> .child’)
jQuery uses the Sizzle engine internally to process various selectors. The selection order of the Sizzle engine is from right to left, so this statement selects .child first, and then filters out the parent element #parent one by one, which makes it about 70% slower than the fastest form.
(5) $(‘#parent .child’)
This statement is the same as the previous one. However, the previous one only selects direct sub-elements, this one can select multi-level sub-elements, so its speed is slower, about 77% slower than the fastest form.
(6) $(‘.child’, $(‘#parent’))
jQuery internally converts this statement into $(‘#parent’).find(‘.child’), which is 23% slower than the fastest form.
Therefore, the best choice is $parent.find(‘.child’). Moreover, since $parent is often generated in the previous operation, jQuery will cache it, so the execution speed is further accelerated.
For specific examples and comparison results, please see here .
4. Don’t overuse jQuery
No matter how fast jQuery is, it cannot be compared with the native javascript method. Therefore, where native methods can be used, try to avoid using jQuery.
Take the simplest selector as an example, document.getElementById(“foo”) is more than 10 times faster than $(“#foo”) .
Let’s look at another example, bind a function to handle the click event for the a element:
$(‘a’).click(function(){
alert($(this).attr(‘id’));
});
This code means that after clicking the a element, the id attribute of the element will pop up. In order to obtain this attribute, you must call jQuery twice in a row, the first time is $(this), and the second time is attr(‘id’).
In fact, this kind of processing is completely unnecessary. A more correct way of writing is to directly use the javascript native method and call this.id:
$(‘a’).click(function(){
alert(this.id);
});
According to the test , the speed of this.id is more than 20 times faster than $(this).attr(‘id’).
5. Do a good job of caching
Selecting a certain web page element is a costly step. Therefore, the use of selectors should be as few as possible, and the selected results should be cached as much as possible to facilitate repeated use in the future.
For example, the following writing is bad writing:
jQuery(‘#top’).find(‘p.classA’);
jQuery(‘#top’).find(‘p.classB’);
A better way is:
var cached = jQuery(‘#top’);
cached.find(‘p.classA’);
cached.find(‘p.classB’);
According to the test , caching is 2-3 times faster than no caching.
6. Use chain writing
A major feature of jQuery is that it allows the use of chain writing.
$(‘div’).find(‘h3’).eq(2).html(‘Hello’);
When using chain writing, jQuery automatically caches the results of each step, so it is faster than non-chain writing. According to the test , chain writing is about 25% faster than non-chain writing (without using cache).
7. Event Delegation
The javascript event model adopts the “bubbling” mode, that is, the events of the child elements will “bubble” upwards step by step and become the events of the parent element.
Using this, the binding of events can be greatly simplified. For example, there is a table (table element) with 100 grids (td element). Now it is required to bind a click event (click) to each grid. Do I need to execute the following command 100 times?
$(“td”).on(“click”, function(){
$(this).toggleClass(“click”);
});
The answer is no, we just need to bind this event to the table element, because after the click event of the td element, this event will “bubble” to the parent element table and be monitored.
Therefore, this event only needs to be bound once to the parent element, instead of 100 times to the child element, which greatly improves performance. This is called the “delegated processing” of the event, that is, the child element “delegates” the parent element to handle the event.
$(“table”).on(“click”, “td”, function(){
$(this).toggleClass(“click”);
});
A better way is to bind the event to the document object.
$(document).on(“click”, “td”, function(){
$(this).toggleClass(“click”);
});
If you want to cancel the binding of the event, use the off() method.
$(document).off(“click”, “td”);
8. Less changes to the DOM structure
(1) It is very expensive to change the DOM structure, so do not use methods such as .append(), .insertBefore() and .insetAfter() frequently.
If you want to insert multiple elements, merge them first, and then insert them all at once. According to the test , the combined insert is nearly 10 times faster than the non-combined insert.
(2) If you want to perform a large amount of processing on a DOM element, you should first use the .detach() method to remove the element from the DOM, and then reinsert it back into the document after processing. According to the test , using the .detach() method is 60% faster than when not using it.
(3) If you want to store data on DOM elements, do not write the following:
var elem = $(‘#elem’);
elem.data(key,value);
But to be written as
var elem = $(‘#elem’);
$.data(elem[0],key,value);
According to the test , the latter writing method is nearly 10 times faster than the former writing method. Because the elem.data() method is defined on the prototype object of the jQuery function, and the $.data() method is defined on the jQuery function, it is not called from the complex jQuery object when it is called, so the speed is much faster. (You can refer to point 10 below here.)
(4) insert html code, the browser native innterHTML () () method of the object than the jQuery html faster .
9. Properly handle loops
Looping is always a time-consuming operation. If you can use complex selectors to select elements directly, don’t use loops to identify the elements one by one.
native javascript methods for recycling and while, than jQuery’s .each () method fast , should give priority to using native methods.
10. Minimize the generation of jQuery objects
Every time you use a selector (such as $(‘#id’)), a jQuery object will be generated. The jQuery object is a very large object with many properties and methods, which will take up a lot of resources. Therefore, try to generate as few jQuery objects as possible.
For example, many jQuery methods have two versions, one is the version used by the jQuery object , and the other is the version used by the jQuery function . The following two examples both take out the text of an element and use the text() method.
You can either use the version for the jQuery object:
var $text = $(“#text”);
var $ts = $text.text();
You can also use the version for jQuery functions:
var $text = $(“#text”);
var $ts = $.text($text);
Since the latter does not function for version jQuery jQuery object through operation, the overhead is relatively small, the speed is faster .
11. Choose the shortest method of scope chain
Strictly speaking, this principle applies to all Javascript programming, not just to jQuery.
We know that Javascript variables use chain scope. When reading a variable, first look for the variable in the current scope. If it cannot be found, go to the upper-level scope to look for the variable. This design makes reading local variables much faster than reading global variables.
Please look at the following two pieces of code, the first piece of code is to read global variables:
var a = 0;
function x(){
a += 1;
}
The second piece of code is to read local variables:
function y(){
var a = 0;
a += 1;
}
When the second code reads the variable a, it does not need to go to the upper scope, so it is five or six times faster than the first code .
Similarly, when you call object methods, closure mode than in prototype mode faster .
prototype mode:
var X = function(name){ this.name = name;}
X.prototype.get_name = function() {return this.name; };
closure mode:
var Y = function(name) {
var y = {name: name };
return {‘get_name’: function() {return y.name;} };};
The same is the get_name() method, and the shutdown mode is faster .
12. Use Pub/Sub mode to manage events
When an event occurs, if you want to perform multiple operations consecutively, it is best not to write the following:
function doSomthing{
doSomethingElse();
doOneMoreThing();
}
Instead, use the event-triggered form:
function doSomething{
$.trigger(“DO_SOMETHING_DONE”);
}
$(document).on(“DO_SOMETHING_DONE”, function(){
doSomethingElse();}
);
You can also consider using deferred objects .
function doSomething(){
var dfd = new $.Deferred();
//Do something async, then…
//dfd.resolve();return dfd.promise();
}
function doSomethingElse(){
$.when(doSomething()).then(//The next thing);
}
(over)