[Post] how to improve the efficiency of Javascript DOM operations

Source: Internet
Author: User

Nicholas explains how to improve the efficiency of Javascript DOM operations!

In web development, a very important role of JavaScript is to operate the Dom. Do you know? Dom operations are very expensive, because this will cause the browser to perform reflux operations, and if too many reflux operations are performed, you will find that your website is getting slower and slower, we should try to reduce Dom operations as much as possible. This is the last article in this series. It provides some guiding principles, such as when to perform operations on the Dom.

[Original] Nicolas C. zakas-speed up your JavaScript, Part 4

Mingda

In the past few weeks, I have introduced several technologies that can speed up the running of JavaScript scripts.

Section 1

Describes how to optimize the cycle.

Section 2

Focuses on optimizing functions.CodeThe queue and memory technologies are introduced to reduce the workload of functions.

Section 3

This article discusses how to convert recursion into an iterative loop or a mode of memory. Section 4 is the last article in this series, which focuses on the impact of too many Dom operations.

 

We all know that Dom operations are very inefficient and not very slow, and this is also one of the common problems that cause performance problems. Why is it slow? Since Dom modification affects the user interface of a webpage, page re-painting is an expensive operation. Too many Dom operations will lead to a series of re-painting operations. To ensure the accuracy of the execution results, all the modifications are executed in sequence. We call this process reflow, which is also one of the most expensive browser operations. Reflux operations may occur in the following situations:

 

* When you add or delete a DOM node.

 

* When setting a style dynamically (such as element. style. width = "10px ").

 

* When obtaining a size value that must be calculated, for example, accessing offsetwidth, clientheight, or other CSS values that need to be calculated (in a dom-compatible browser, you can get it using the getcomputedstyle function; in IE, it can be obtained through the currentstyle attribute ).

 

The key to solving the problem is to limit the number of backflows caused by Dom operations. Most browsers do not update the DOM during Javascript execution. Correspondingly, these browsers put Dom operations in a queue, and once executed in order after the Javascript script is executed. That is to say, during Javascript execution, the user cannot interact with the browser until a backflow operation is executed. (The out-of-control script dialog box triggers the backflow operation because it executes an operation to stop JavaScript Execution and updates the user interface)

 

There are two basic methods to reduce the reflux operation caused by Dom modification. First, make as many preparations as possible before performing operations on the current Dom. A typical example is to add many DOM nodes to the Document Object:

 

/*
For (VAR I = 0; I <items. length; I ++ ){
VaR item = Document. createelement ("Li ");
Item. appendchild (document. createtextnode ("option" + I );
List. appendchild (item );
}
*/

This code is very inefficient because it modifies the current Dom structure in each loop. To improve performance, we need to minimize this number of times. In this case, the best way is to create a document fragment as a temporary container that has created element elements, the last time you add the container content to the parent node:

 

 
/*
VaR fragment = Document. createdocumentfragment ();
For (VAR I = 0; I <items. length; I ++ ){
VaR item = Document. createelement ("Li ");
Item. appendchild (document. createtextnode ("option" + I );
Fragment. appendchild (item );
}
List. appendchild (fragment );
*/

The adjusted Code only modifies the structure of the current Dom once in the last row. Before that, we use document fragments to save the intermediate results. Because there is no visible content in the document fragments, such repair and modification will not trigger backflow. In fact, the File Fragment cannot be added to the Dom. We need to pass it as a parameter to the appendchild function. What we actually add is not the File Fragment itself, but all the child elements under it.

 

Another method to avoid unnecessary backflow operations is to delete the elements to be operated from the current Dom structure before dom operations. There are two basic methods to delete an element:

 

1. Delete objects in the true sense through removechild () or replaceChild.

 

2. Set the display style of the element to "NONE ".

 

Once the modification operation is complete, the above process needs to be reversed and the deleted elements should be added to the current Dom structure again. Let's take the above example to explain:

 

 
/*
List. style. Display = "NONE ";
For (VAR I = 0; I <items. length; I ++ ){
VaR item = Document. createelement ("Li ");
Item. appendchild (document. createtextnode ("option" + I );
List. appendchild (item );
}
List. style. Display = "";
*/

After setting the display style of the List to "NONE", the element is deleted from the current Dom structure because the node is no longer visible. Adding sub-elements to the display attribute does not trigger backflow before setting the display attribute back to the default value.

 

In addition, the style attribute is used to modify the appearance of an element. For example:

 

/*
Element. style. backgroundcolor = "blue ";
Element. style. color = "red ";
Element. style. fontsize = "12em ";
*/

This code modifies three styles and triggers three backflow operations. Each time you modify the style attribute of an element, the reflux operation is triggered. If you want to modify many styles of an element at the same time, the best way is to put these styles under a class and then directly modify the class of the element, which is much better than modifying the style of an element separately. For example:

 

 
/*
. Newstyle {
Background-color: blue;
Color: red;
Font-size: 12em;
}
*/

In this way, in JavaScript code, you only need the following line of code to modify the style:

 

 
/*
Element. classname = "newstyle ";
*/

Modifying the class attribute of an element applies all styles to the target element at a time, and only one backflow operation is triggered. This is not only more effective, but also easier to maintain.

 

Since Dom is slow in almost all cases, it is necessary to cache the retrieved DOM data. This method is especially important for obtaining attributes that will trigger backflow operations (such as offsetwidth), even in general cases. The following is an exaggerated example:

 

/*
Document. getelementbyid ("mydiv"). style. Left = Document. getelementbyid ("mydiv"). offsetleft +
Document. getelementbyid ("mydiv"). offsetwidth + "PX ";
*/

Getelementbyid () is called three times, which is a big problem. Dom access is very expensive, and these three calls access the same element, it may be better if we write like below:

 

 
/*
VaR mydiv = Document. getelementbyid ("mydiv ");
Mydiv. style. Left = mydiv. offsetleft + mydiv. offsetwidth + "PX ";
*/

We removed some redundant operations and now the number of Dom operations has been reduced. We should buffer the DOM values that have been used more than once to avoid unnecessary performance consumption.

 

Alternatively, the main cause of slow attribute access is the htmlcollection object. These objects are of the object type. This object is used as long as the Dom needs to return a group of nodes. That is to say, the return values of the childnodes attribute and getelementsbytagname () belong to this situation. We may often use htmlcollection as an array, but it is actually an object automatically changed according to the DOM structure. Every time you access the attributes of an htmlcollection object, it will perform a full match on all the nodes in the Dom, which means the following code will lead to an endless loop:

 

/*
VaR divs = Document. getelementsbytagname ("Div ");
For (VAR I = 0; I <Divs. length; I ++) {// Infinite Loop
Document. Body. appendchild (document. createelement ("Div "));
}
*/

Why does this Code become an endless loop? In each loop, a div element is added to the document and the divs set is updated. That is to say, the index of the Loop will never exceed Divs. length value, because Divs. the value of length increases with a loop. Each time Divs. length is accessed, a set object is updated, which is more expensive than accessing the Length attribute of a common array. When you operate an htmlcollection object, you should minimize the number of accesses as much as possible. You can cache the Length attribute in a local variable, in this way, the cycle efficiency can be greatly improved.

 

 
/*
VaR divs = Document. getelementsbytagname ("Div ");
For (VAR I = 0, Len = Divs. length; I <Len; I ++) {// not an infinite loop
Document. Body. appendchild (document. createelement ("Div "));
}
*/

The modified code is no longer an endless loop, because the Len value remains unchanged during each loop. Caching attribute values not only improves efficiency, but also ensures that the document does not perform more than one query.

 

This is the last article in the "speed up your JavaScript" series.Article, I hope that you now know how to prevent the script from getting out of control dialog box, and how to make your script run faster. Many of the techniques I 've mentioned have already been mentioned. I just want to organize them together so that you can easily find the information. If you have any better topics that need to be sorted out by me, let me know in the comments, or contact me directly.

Original address: http://www.v-ec.com/dh20156/article.asp? Id = 216

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.