How does the JQuery each () function optimize the performance of the circular DOM structure?

Source: Internet
Author: User

If jQuery is used only at the usage level, but does not know its specific implementation, it is very easy to use problems. This is why I have never liked jQuery recently. The API settings of this framework may mislead people.
Copy codeThe Code is as follows:
$. Fn. beautifyTable = function (options ){
// Define the default configuration item and overwrite it with options
Return this. each (function (){
Var table = $ (this ),
Tbody = table. children ('tbody '),
Tr = tbody. children ('tr '),
Th = tbody. children ('th '),
Td = tbody. children ('td ');
// Class with separate content
Table. addClass (option. tableClass );
Th. addClass (options. headerClass); // 1
Td. addClass (options. cellClass); // 2
// The class of the parity row
Tbody. children ('tr: even'). addClass (options. evenRowClass); // 3
Tbody. children ('tr: odd'). addClass (options. oddRowClass); // 4
// Alignment
Tr.children('th,td').css ('text-align ', options. align); // 5
// Add mouse Suspension
Tr. bind ('mouseover', addActiveClass); // 6
Tr. bind ('mouseout', removeActiveClass); // 7
// Click to change color
Tr. bind ('click', toggleClickClass); // 8
});
};

In general, this code is good, with clear thinking, clear logic, and a clear explanation of what you want to do. However, according to the author, when there are 120 rows in the table, IE indicates that the script has been running for too long. Obviously, from the perspective of performance, this function is not efficient, or even extremely low.

As a result, we started to analyze the Code. this is a standard jQuery plug-in function, with a typical return this. each (function (){... };); Form of code. If the author writes this code without thinking about it, he should be aware of what a function of jQuery has done.

JQuery. most of the functions under fn are called by an each. The so-called each essentially traverses the selected elements and performs specified operations on an element. Let's take a look at the code above and how much traversal is done. Here we assume that only 120 rows are selected, each row has 6 columns, and the header of one row is added:
Traverse th and add headerClass with 6 elements.
Traverse td and add cellClass. The number of elements is 6*120 = 720.
Find the odd number from all tr and traverse all tr at a time. The number of elements is 120.
Traverse the odd tr and add evenRowClass. The number of elements is 120/2 = 60.
Find the even number from all tr, and traverse all tr at a time. The number of elements is 120.
Traverse the even number of tr and add oddRowClass. The number of elements is 120/2 = 60.
Traverse all th and td and add text-align. The number of elements is 120*6 + 6 = 726.
Traverse all tr and add a mouseover event. The number of elements is 120.
Traverse all tr and add a mouseout event. The number of elements is 120.
Traverse all tr and add a click event. The number of elements is 120.
For convenience, we simply assume that it takes 10 ms to access an element during traversal. How long does this function take? This function has a total of 2172 elements, which takes 21720 ms, that is, 21 seconds. Obviously, IE must have reported that the script has been executed for too long.

Knowing the cause of low efficiency, we need to solve it fundamentally. Naturally, we need to find ways to merge loops. At first glance, follow the numbers in the notes in the above Code, at least the following points can be merged:
3 and 4 can be combined into a loop, from 120 + 60 + 120 + 60 to 120, reducing by 240. 1, 2, and 5 can be combined into a loop, from 6 + 720 + 726 to 726, reducing by 726. 6, 7, and 8 can be combined into a cycle, from 120 + 120 + 120 to 120, reducing by 240. Further, 3, 4, and 6, 7, and 8 can be combined into a loop, which is reduced by 120. To sum up, we reduced the number of element operations by 240 + 726 + 240 + 120 = 1326, totaling 13260 ms. After optimization, our function time is changed to 21720-13260 = 8460 ms, that is, 8 s.
There may be a question here. In terms of table structure, all th and td elements must be within tr, so why don't we put the three steps 1, 2, and 5 in the same cycle of tr to form a nested loop? Isn't that faster?
There are two main reasons for not doing this:
First, no matter where the three elements 1, 2, and 5 are put, the access to all th and td elements is not reduced.
On the other hand, the $ ('th, td ') selector is translated into two calls to the getElementsByTagName function in sizzle. It gets all th for the first time and all td for the second time, then merge the set. Because getElementsByTagName is a built-in function, it can be considered that this function does not carry loops, that is, the complexity is O (1). The same set is merged using Array-related functions, is the memory operation, the complexity is also O (1 ).

Otherwise, if the $ ('th, 'td) selector is used in the loop of the tr element, the getElementsByTagName is called twice on the tr element, no matter which element calls the function, the function execution time is the same, so it is used in loop tr, instead of 119*2 more function calls, the efficiency is not increased or decreased.
It can be seen that the basic knowledge of the sizzle selector is also an important aspect to help optimize jQuery code.
Do not use javascript For anything.

According to the previous optimization, the time has been reduced from 21 seconds to 8 seconds, but the 8 seconds is obviously unacceptable.
Further analysis of our code, in fact, loop traversal is language-level content, and its speed should be quite fast. The operations for each element are functions provided by jQuery. Compared with traversal, they occupy the majority of resources. If the access element in the traversal process is 10 ms, you can say that the execution of an addClass is at least Ms.

Therefore, in order to further optimize the efficiency, we have to reduce the number of operations on elements. Review the code carefully and find that this function has many style modifications, including at least:
Add class to all th.
Add class to all td.
Add a class to the tr parity row.
Add a text-align style to all th and td.
In fact, we know that CSS itself has a child selector, and the efficiency of the browser native parsing CSS is much higher than that of letting javascript add class to elements one by one.

Therefore, if CSS is controllable, this function should not have the headerClass and cellClass configuration items, but should be configured in CSS as much as possible:
Copy codeThe Code is as follows:
. Beautiful-table th {/* headerClass content */}
. Beautiful-table td {/* cellClass content */}

Furthermore, for the tr parity row style, you can use the nth-child pseudo class in Some browsers to implement it. In this respect, you can use the feature detection, add styles using addClass only in browsers that do not support this pseudo class. Of course, if you only want to optimize the IE series, this one can be ignored.

For nth-child pseudo-class detection, you can use the following idea: Create a stylesheet and create another rule, such as # test span: nth-child (odd) {display: block ;}. Create an HTML structure, a div with the id of test, and put three spans in it.

Add stylesheet and div to the DOM tree. View the display style of 1st and 3rd spans during runtime. If it is block, this pseudo class is supported. Delete the created stylesheet and div. Do not forget to cache the test results. Finally, you can use css to optimize the text-align style for all th and td elements. Since you do not know which align is added, write more styles:
Copy codeThe Code is as follows:
/* CSS style */
. Beautiful-table-center th,. beautiful-table-center td {text-align: center! Important ;}
. Beautiful-table-rightright th,. beautiful-table-rightright td {text-align: rightright! Important ;}
. Beautiful-table-left th,. beautiful-table-left td {text-align: left! Important ;}
/* Javascript */
Table. addClass ('betiful-table-'+ options. align );

Of course, the optimization mentioned above is based on the control of CSS. If CSS styles cannot be accessed, for example, this is a common plug-in function, it will be used by third parties that are completely uncontrollable. What should we do? There is no way at all:
Find all CSS rules on the page, such as document. styleSheets. Traverse all rules and take out headerClass and cellClass in the configuration item. Extract all styles from several required classes and assemble them into new selectors, such as beautiful-table th. Use the created selector to generate a new stylesheet and add it to the DOM tree. You can only add the class beautiful-table to the table.

Of course, the above practice is actually quite time-consuming. After all, we have to traverse stylesheet and create stylesheet. Is it a great help for efficiency improvement? It depends on the size of the page and whether it is used depends on the specific needs of function designers, here is a policy.

In general, by executing javascript as little as possible and handing over more styling tasks to CSS, the browser's rendering engine can further optimize the function, assuming that the call to addClass and css requires 120 ms, this optimization directly eliminates the original 726 + 846 = operations, saving 8 to Ms of time (of course there are exaggerated components, but for the consumption of the entire function, this is indeed a huge one ).

This article only involves the analysis, details, and optimization of jQuery's entire operation process, some basic optimization methods are not mentioned. For example, the entire table is removed from the DOM tree first, and all operations are completed before putting it back into the DOM to reduce repainting. Change mouseover and mouseout to mouseenter and mouseleave to reduce the execution of repeated event functions caused by the correct event bubble model. For simple elements such as th and td, the native getElementsByTagName is preferred to eliminate the time of sizzle analysis selector.

Finally, this article just wants to explain that for front-end developers, although the browser may be a black box, many frameworks, tools, and libraries are open, A certain degree of understanding before use will inevitably help improve personal technology and optimize the quality of the final product. It is a very taboo to "know it, but don't know why.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.