Web Performance Optimization-javascript skills

Source: Internet
Author: User
This article introduces in detail some small details about the performance in Web development. Starting with JavaScript itself, it introduces some functions and programming rules to be avoided in JavaScript, for example, eval's drawbacks: functionscopechain and String usage JavaScript is a well-developed front-end development language, which is widely used in today's web development, especially for Web 2.0 applications. As Web 2.0 becomes more and more popular today, we will find that there will be a lot of JavaScript code in our web application projects, and more in the future. JavaScript, as a language for interpretation and execution, and its single-threaded mechanism, determines the performance problem as a weakness of JavaScript. It is also a problem that web software engineers need to pay great attention to when writing JavaScript, especially for Web 2.0 applications. Most web software engineers have encountered poor performance of the developed Web 2.0 application, mainly because of insufficient JavaScript performance and heavy browser load. However, it is not easy to solve the performance problem of such interpretation execution and single-threaded operating language. This article will focus on some tips and best practices on JavaScript performance tuning during development, as well as some methods for optimizing the performance of JavaScript operations on DOM nodes.

Introduction
Web development often encounters performance problems, especially for today's Web2.0 applications. JavaScript is the most widely used Web development language today. Most of the performance problems of Web applications are caused by poor performance of JavaScript scripts written by programmers, it includes the performance issues of the JavaScript language and the performance issues when it interacts with the DOM. This article mainly discusses how to avoid such problems as much as possible, so as to maximize the performance of Web applications.

JavaScript Performance Tuning
Because of its single-line process and interpretation execution, the JavaScript language has many performance problems, so there are many improvements.

Eval Problems:
Compare the following code:
Listing 1. eval Problems

The Code is as follows:


Var reference ={}, props = "p1 ";
Eval ("reference." + props + "= 5 ")
Var reference ={}, props = "p1 ";
Reference [props] = 5


Code with "eval" is more than 100 times slower than code without "eval.
The main reason is that JavaScript code performs operations similar to "pre-compilation" before execution: First, it creates an activity object in the current execution environment, and set the variables declared with var to the attributes of the active object. However, the value assigned to these variables is undefined, and the functions defined by the function are also added as the attributes of the active object, and their values are exactly the definitions of functions. However, if you use "eval", the code in "eval" (actually a string) cannot identify its context in advance and cannot be parsed and optimized in advance, you cannot perform the pre-compilation operation. Therefore, its performance will be greatly reduced.

Function usage:
Compare the following code:
Listing 2. function usage

The Code is as follows:


Var func1 = new Function ("return arguments [0] + arguments [1]");
Func1 (10, 20 );
Var func2 = function () {return arguments [0] + arguments [1]};
Func2 (10, 20 );


This is similar to the "eval" method mentioned earlier. Here, "func1" is much more efficient than "func2", so we recommend the second method.

Scope chain of a function ):
When JavaScript code is interpreted and executed, it analyzes the current variables in advance and classifies them into different levels. Generally:
Local variables are placed in level 1 (shallow), and global variables are placed in level 2 (deep ). If you enter the "with" or "try-catch" code block, a new level will be added to put the variables in "with" or "catch" into the shortest layer (Layer 1 ), and deepen the previous layers in sequence.
Refer to the following code:
Listing 3. Function scope chain

The Code is as follows:


Var myObj =... ..
... ..
Function process (){
Var images = document. getElementsByTagName ("img "),
Widget = document. getElementsByTagName ("input "),
Combination = [];
For (var I = 0; I <images. length; I ++ ){
Combination. push (combine (images [I], widget [2 * I]);
}
MyObj. container. property1 = combination [0];
MyObj. container. property2 = combination [combination. length-1];
}


Here we can see that "images", "widget", and "combination" are local variables in Layer 1. "Document" and "myObj" are global variables in Layer 2.
The lighter the layer where the variable is located, the faster the access (read or modify) is. The deeper the layer, the slower the access speed. Therefore, the access speed of "images", "widget", and "combination" is faster than that of "document" and "myObj. Therefore, we recommend that you use local variables as much as possible. See the following code:
Listing 4. Using local variables

The Code is as follows:


Var myObj =... ..
... ..
Function process (){
Var doc = document;
Var images = doc. getElementsByTagName ("img "),
Widget = doc. getElementsByTagName ("input "),
Combination = [];
For (var I = 0; I <images. length; I ++ ){
Combination. push (combine (images [I], widget [2 * I]);
}
MyObj. container. property1 = combination [0];
MyObj. container. property2 = combination [combination. length-1];
}


We use the local variable "doc" to replace the global variable "document", which can improve the performance, especially for functions that use a large number of global variables.
Let's look at the following code:
Listing 5. Use with caution

The Code is as follows:


Var myObj =... ..
... ..
Function process (){
Var doc = document;
Var images = doc. getElementsByTagName ("img "),
Widget = doc. getElementsByTagName ("input "),
Combination = [];
For (var I = 0; I <images. length; I ++ ){
Combination. push (combine (images [I], widget [2 * I]);
}
With (myObj. container ){
Property1 = combination [0];
Property2 = combination [combination. length-1];
}
}


The "with" keyword makes the code more concise and clear, but the performance will be affected. As mentioned earlier, when we enter the "with" code block, "combination" is changed from the original layer 1 to the Layer 2, which greatly reduces the efficiency. So we can compare it with the original code:
Listing 6. Improving

The Code is as follows:


Var myObj =... ..
... ..
Function process (){
Var doc = document;
Var images = doc. getElementsByTagName ("img "),
Widget = doc. getElementsByTagName ("input "),
Combination = [];
For (var I = 0; I <images. length; I ++ ){
Combination. push (combine (images [I], widget [2 * I]);
}
MyObj. container. property1 = combination [0];
MyObj. container. property2 = combination [combination. length-1];
}


However, this is not the best method. JavaScript has a special feature. For object objects, the deeper the attribute access level, the lower the efficiency. For example, the "myObj" here has been accessed to layer 3rd, we can improve it as follows:
Listing 7. narrowing down the object access level

The Code is as follows:


Var myObj =... ..
... ..
Function process (){
Var doc = document;
Var images = doc. getElementsByTagName ("img "),
Widget = doc. getElementsByTagName ("input "),
Combination = [];
For (var I = 0; I <images. length; I ++ ){
Combination. push (combine (images [I], widget [2 * I]);
}
Var ctn = myObj. container;
Ctn. property1 = combination [0];
Ctn. property2 = combination [combination. length-1];
}


We use local variables to replace the "iner" Object in layer 2nd of "myObj. If there is a large number of such accesses to the deep properties of the object, you can refer to the above method to improve performance.

String correlation
String concatenation
This code is often seen:
Listing 8. Simple String concatenation

The Code is as follows:


Str + = "str1" + "str2"


This is a common method for concatenating strings. However, this method creates and destroys some temporary variables, which affects the performance. Therefore, we recommend that you splice them as follows:
Listing 9. String Array concatenation

The Code is as follows:


Var str_array = [];
Str_array.push ("str1 ");
Str_array.push ("str2 ");
Str = str_array.join ("");


Here we use the "join" method of array to concatenate strings, especially when the program's earlier version of Internet Explorer E (IE6) is running, there will be significant performance improvements.
Of course, the latest browsers (such as Firefox Firefox3 + and IE8 +) have optimized String concatenation. We can also write the following code:
Listing 10. Fast String concatenation

The Code is as follows:


Str + = "str1"
Str + = "str2"


The new browser optimizes "+ =", and the performance is slightly faster than the "join" method of the array. In the near future, the browser may optimize "+", so we can directly write "str + =" str1 "+ ".

Implicit type conversion
Refer to the following code:
Listing 11. implicit type conversion

The Code is as follows:


Var str = "12345678", arr = [];
For (var I = 0; I <= s. length; I ++ ){
Arr. push (str. charAt (I ));
}


Here we call the "charAt" method of the string in every loop, but because we assign the constant "12345678" to "str ", so "str" is actually not a string object. Every time it calls the "charAt" function, it will temporarily construct a String object with a value of "12345678, call the "charAt" method and release the temporary String object. We can make some improvements:
Listing 12. Avoid implicit type conversion

The Code is as follows:


Var str = new Stirng ("12345678"), arr = [];
For (var I = 0; I <= s. length; I ++ ){
Arr. push (str. charAt (I ));
}


In this way, the variable "str" as a string object will not have this implicit type conversion process, which will significantly improve the efficiency.

String Matching
JavaScript has a RegExp object and supports regular expression matching for strings. Is a good tool, but its performance is not very good. On the contrary, some basic methods of String objects are very efficient, such as "substring", "indexOf", and "charAt, when we need to use a regular expression to match a string, consider the following:
Whether the problem can be solved through the basic methods supported by the string object itself.
Whether "substring" can be used to narrow the range of regular expressions.
These methods can effectively improve program efficiency.
For more information about regular expression objects, see the following code:
Listing 13. Regular Expressions

The Code is as follows:


For (var I = 0; I <= str_array.length; I ++ ){
If (str_array [I]. match (/^ s * extra \ s /)){
........................
}
}


Here, we pass "/^ s * extra \ s/" to the "match" method, which will affect the efficiency, it constructs a regular expression object with a temporary value of "/^ s * extra \ s/", executes the "match" method, and destroys the temporary regular expression object. We can do this:
Listing 14. Using Variables

The Code is as follows:


Var sExpr =/^ s * extra \ s /;
For (var I = 0; I <= str_array.length; I ++ ){
If (str_array [I]. match (sExpr )){
........................
}
}


In this way, there will be no temporary objects.
SetTimeout and setInterval
The "setTimeout" and "setInterval" functions can accept string variables, but they bring performance issues similar to the previously mentioned "eval". Therefore, it is recommended to directly pass in the function object itself.

Early exit
Refer to the following two sections of code:
Listing 15. Early exit

The Code is as follows:


// Code 1
Var name =... .;
Var source = ...... ;
If (source. match (/...... /)){
.................................
}
// Code 2
Var name =... .;
Var source = ...... ;
If (name. indexOf (... ) & Source. match (/...... /)){
.................................
}


Code 2 has an additional pair of "name. indexOf (... ), So that each time the Program reaches this section, it will first execute the "indexOf" judgment, and then execute the "match ", if "indexOf" is much more efficient than "match", this will reduce the number of "match" executions, thus improving the efficiency to a certain extent.
--------------------------------------------------------------------------------
DOM operability Optimization
JavaScript development is inseparable from DOM operations. Therefore, optimizing the performance of DOM operations is also very important in Web development.
Repaint and Reflow
Repaint is also called Redraw. It refers to a repainting action that does not affect the structure and layout of the current DOM. The following action will generate a Repaint action:
Invisible (visibility style attribute)
Color or image changes (background, border-color, color style attributes)
Does not change the page element size, shape, and position, but changes its appearance
Reflow is a more significant change than Repaint. It mainly occurs when the DOM tree is operated, any changes to the DOM structure and layout will generate a Reflow. However, when an element's Reflow operation occurs, all its parent elements and child elements will generate a Reflow, and finally the Reflow will inevitably lead to repainting. For example, the following action will generate a Repaint action:

Browser window changes
Add and delete DOM nodes
Trigger of some operations to change the page element size, shape, and position
Reduce Reflow
According to the introduction of Reflow and Repaint, each Reflow will consume more resources than its Repaint. We should minimize the occurrence of Reflow, or convert it to code that will only trigger the Repaint operation.
Refer to the following code:
Listing 16. reflow Introduction

The Code is as follows:


Var pDiv = document. createElement ("p ");
Document. body. appendChild (pDiv); ----- reflow
Var cDiv1 = document. createElement ("p ");
Var cDiv2 = document. createElement ("p ");
PDiv. appendChild (cDiv1); ----- reflow
PDiv. appendChild (cDiv2); ----- reflow


This is the code we often access, but this code will generate three reflows. Let's look at the following code:
Listing 17. Reduce reflow

The Code is as follows:


Var pDiv = document. createElement ("p ");
Var cDiv1 = document. createElement ("p ");
Var cDiv2 = document. createElement ("p ");
PDiv. appendChild (cDiv1 );
PDiv. appendChild (cDiv2 );
Document. body. appendChild (pDiv); ----- reflow


Here there is only one reflow, so we recommend this DOM node operation method.
There is also a reference mode for the solution with fewer Reflow operations:
Listing 18. Using display to reduce reflow

The Code is as follows:


Var pDiv = document. getElementById ("parent ");
PDiv. style. display = "none" ----- reflow
PDiv. appendChild (cDiv1 );
PDiv. appendChild (cDiv2 );
PDiv. appendChild (cDiv3 );
PDiv. appendChild (cDiv4 );
PDiv. appendChild (cDiv5 );
PDiv. style. width = "100px ";
PDiv. style. height = "100px ";
PDiv. style. display = "block" ----- reflow


Hide pDiv first and then display. In this way, operations between hide and display will not generate any Reflow, improving the efficiency.

Special measurement attributes and Methods
DOM elements have special access to measurement attributes and call methods, which also triggers Reflow. The typical examples are the "offsetWidth" attribute and the "getComputedStyle" method.
Figure 1. Special measurement attributes and Methods

These measurement attributes and methods are roughly as follows:

The Code is as follows:


OffsetLeft
OffsetTop
OffsetHeight
OffsetWidth
ScrollTop/Left/Width/Height
ClientTop/Left/Width/Height
GetComputedStyle ()
CurrentStyle (in IE ))


The access and call of these attributes and methods will trigger the generation of Reflow. We should try to minimize the access and call to these attributes and Methods. refer to the following code:
Listing 19. Special measurement attributes

The Code is as follows:


Var pe = document. getElementById ("pos_element ");
Var result = document. getElementById ("result_element ");
Var pOffsetWidth = pe. offsetWidth;
Result. children [0]. style. width = pOffsetWidth;
Result. children [1]. style. width = pOffsetWidth;
Result. children [2]. style. width = pOffsetWidth;


............ Other modifications ............
Here we can use a temporary variable to cache the value of "offsetWidth" so that we do not need to access the "offsetWidth" attribute every time. This method is very suitable in the loop and can greatly improve the performance.

Style-related
We certainly often see the following code:
List 20. Style-related

The Code is as follows:


Var sElement = document. getElementById ("pos_element ");
SElement. style. border = '1px solid red'
SElement. style. backgroundColor = 'sil'
SElement. style. padding = '2px 3px'
SElement. style. marginLeft = '5px'


But we can see that every style change here produces Reflow. To reduce this situation, we can do this:
Solution 1:
Listing 21. className Solution

The Code is as follows:


. Class1 {
Border: '1px solid red'
Background-color: 'silver'
Padding: '2px 3px'
Margin-left: '5px'
}
Document. getElementById ("pos_element"). className = 'class1 ';


Replace style with class to reduce the number of Reflow or repainting times to one.

Solution 2:
Listing 22. cssText Solution

The Code is as follows:


Var sElement = document. getElementById ("pos_element ");
Var newStyle = 'border: 1px solid red; '+ 'background-color: silver;' +
'Padding: 2px 3px; '+ "margin-left: 5px ;"
SElement.style.css Text + = newStyle;


Setting all styles at one time is also a way to reduce Reflow to improve performance.
XPath
A page usually contains more than 1000 page elements. It usually takes some time to locate specific elements. If you use id or name to locate objects, the efficiency may not be too slow. If you use other attributes of an element (such as className) to locate objects, the efficiency may be unsatisfactory. Some elements can only be retrieved by traversing all elements (getElementsByTagName) and then filtering. This is more inefficient. Here we recommend that you use XPath to find elements, which is supported by many browsers.
Listing 23. XPath Solution

The Code is as follows:


If (document. evaluate ){
Var tblHeaders = document. evaluate ("// body/p/table/th ");
Var result = tblHeaders. iterateNext ();
While (result ){
Result. style. border = "1px dotted blue ";
Result ..................
Result = xpathResult. iterateNext ();
}
} Else {// getElementsByTagName ()......
// Handle situations where the browser does not support XPath
....................................
}


The search engine of the browser XPath optimizes the search efficiency and greatly shortens the return time of the results.

HTMLCollection object
This is a special type of objects. They are a bit like arrays, but not entirely arrays. The returned values of the following methods are generally HTMLCollection objects:
Document. images, document. forms
GetElementsByTagName ()
GetElementsByClassName ()
These HTMLCollection objects are not a fixed value but a dynamic result. They are the return values of some special queries. In the following cases, they will re-execute the previous query and get the new return values (query results ), in most cases, the returned values are the same as those of the previous one or several times:

Length attribute
A specific Member
Therefore, access to these attributes and members by HTMLCollection objects is much slower than that by arrays. Of course, there are also exceptions. Opera and Safari can handle this situation well without too many performance problems.
Refer to the following code:
Listing 24. HTMLConnection object

The Code is as follows:


Var items = ["test1", "test2", "test3 ",.................. ];
For (var I = 0; I <items. length; I ++ ){
....................................
}
Var items = document. getElementsByTagName ("p ");
For (var I = 0; I <items. length; I ++ ){
.......................................... .
}


The efficiency of the code at both ends is much slower than that in the previous section, because every loop will have "items. length will lead to "document. getElementsByTagName (..) "method is called again, which is the cause of the significant reduction in efficiency. We can solve this problem as follows:
Listing 25. HTMLConnection object Solution

The Code is as follows:


Var items = document. getElementsByTagName ("p ");
Var len = items. length
For (var I = 0; I <len; I ++ ){
.......................................... .
}


In this way, the efficiency is basically the same as that of a common array.
Dynamically create a script tag
Loading and executing a JavaScript script takes some time. In our program, sometimes some JavaScript scripts are not used after being loaded (for example: functions in the script have never been called ). Loading these scripts only takes up CPU time and increases memory consumption, reducing the performance of Web applications. Therefore, it is recommended to dynamically load JavaScript script files, especially those script files that consume a large amount of resources.
Listing 26. Creating a script tag

The Code is as follows:


If (needXHR ){
Document. write ("

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.