Home > Web Front-end > JS Tutorial > body text

Web performance optimization - javascript performance tuning_javascript skills

WBOY
Release: 2016-05-16 17:44:56
Original
890 people have browsed it

JavaScript is a relatively complete front-end development language and is widely used in today's web development, especially in 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 there will be more and more in the future. As an interpreted and executed language, and its single-thread mechanism, JavaScript determines that performance is the weakness of JavaScript. It is also an issue that web software engineers need to pay great attention to when writing JavaScript, especially for Web 2.0 applications. The vast majority of web software engineers have more or less encountered the problem of poor performance of the Web 2.0 applications they developed. The main reasons are insufficient JavaScript performance and overloaded browsers. However, it is not easy to solve the performance problem of such an interpreted and single-threaded language. This article will focus on some tips and best practices for JavaScript performance tuning during development, and will also cover some methods for performance tuning of JavaScript operating DOM nodes.

Introduction
Performance issues are often encountered in Web development, especially for today's Web2.0 applications. JavaScript is the most widely used Web development language today. A large part of the performance problems of Web applications are caused by the poor performance of JavaScript scripts written by programmers, including performance problems of the JavaScript language itself and its interaction with the DOM. performance issues. This article mainly discusses how to avoid as many such problems as possible, thereby maximizing the performance of web applications.

JavaScript Performance Tuning
Due to its single-threaded and interpreted execution characteristics, the JavaScript language has many performance issues, so there are areas for improvement. There are quite a few.

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

Copy code 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: JavaScript code will perform a similar "pre-compilation" operation before execution: it will first create an active object in the current execution environment, and set those variables declared with var as attributes of the active object, but At this time, the assignments of these variables are all undefined, and those functions defined with function are also added as attributes of the active object, and their values ​​are exactly the definition of the function. However, if you use "eval", the code in "eval" (actually a string) cannot recognize its context in advance and cannot be parsed and optimized in advance, that is, precompiled operations cannot be performed. Therefore, its performance will be greatly reduced.

Usage of Function:
Compare the following code:
Listing 2. Usage of function
Copy code 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);

Similar premise here For the "eval" method, the efficiency of "func1" here will be much worse than that of "func2", so it is recommended to use the second method.

Scope chain of the function:
JavaScript code is interpreted and executed. When entering the function, it will pre-analyze the current variables and classify these variables into Different levels (levels), generally speaking:
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, that is, the variables in "with" or "catch" will be placed in the shallowest level (level 1), and the previous levels will be deepened in sequence.
Refer to the following code:
Listing 3. Function scope chain
Copy code Code 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" belong to local variables in layer 1. "document", "myObj" belong to global variables, in layer 2.
The shallower the layer where the variable is located, the faster the access (read or modify) speed, and the deeper the layer, the slower the access speed. Therefore, the access speed to "images", "widget" and "combination" here is faster than that of "document" and "myObj". Therefore, it is recommended to use local variables as much as possible, as shown in the following code:
Listing 4. Using local variables
Copy code 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 local variable "doc" instead of global variable "document", which can improve performance, especially for functions that use a large number of global variables .
Look at the following code again:
Listing 5. Use with caution with
Copy code code 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];
}
}

With the "with" keyword, we make the code more concise and clear, but the performance will be affected. As mentioned before, when we enter the "with" code block, the "combination" changes from the original layer 1 to layer 2, so the efficiency will be greatly reduced. So for comparison, still use the original code:
Listing 6. Improvement with
Copy code 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];
}

But this is not the best way. JavaScript has a characteristic. For object objects, the deeper the attribute access level, the lower the efficiency. For example, "myObj" here has accessed the third layer. We can improve it like this:
Listing 7. Reduce the object access level
Copy the code 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 second layer of "myObj" "container" object. If there are a large number of such accesses to the deep properties of the object, you can refer to the above methods to improve performance.

String related
String splicing
I often see code like this:
Listing 8. Simple string splicing
Copy code The code is as follows:

str = “str1” “str2”

This is the common way we splice strings, but this method will create and destroy some temporary variables, which affects performance, so it is recommended to use the following method to splice:
Listing 9. String array method Splice
Copy code The code is as follows:

var str_array = [];
str_array.push(“str1”);
str_array.push(“str2”);
str = str_array.join(“”);

Here we use array (array )'s "join" method implements string splicing, especially when running on the old version of Internet Explorer (IE6), there will be a very obvious performance improvement.
Of course, the latest browsers (such as Firefox3, IE8, etc.) have optimized string splicing. We can also write like this:
Listing 10. Quick string splicing
Copy code The code is as follows:

str = "str1"
str = "str2"

The new browser has optimized "=", and the performance is slightly faster than the "join" method of the array. In the near future, updated versions of browsers may also optimize " ", so then we can directly write: str = "str1" "str2".

Implicit type conversion
Refer to the following code:
Listing 11. Implicit type conversion
Copy code The code is as follows:

var str = “12345678”, arr = [];
for(var i = 0; i <= s.length; i ){
arr.push( str.charAt(i));
}

Here we will call the string in each loop "charAt" method, but since we assign the constant "12345678" to "str", "str" ​​is not actually a string object here. Every time it calls the "charAt" function, it will temporarily construct a value of The string object of "12345678", then calls the "charAt" method, and finally releases the string temporary object. We can make some improvements:
Listing 12. Avoiding implicit type conversions
Copy code Code 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, in this way, the efficiency will be significantly improved.

String matching
JavaScript has a RegExp object that supports regular expression matching on strings. It's a great tool, but its performance isn't very good. On the contrary, some basic methods of the string object (String) itself are very efficient, such as "substring", "indexOf", "charAt", etc. When we need to use regular expressions to match strings, we can consider it. :
Is it possible to solve the problem with the basic methods supported by the string object itself.
Is it possible to use "substring" to narrow the range of regular expressions?
These methods can effectively improve the efficiency of the program.
There is one more thing to note about the regular expression object. Please refer to the following code:
Listing 13. Regular expression
Copy Code The code is as follows:

for(var i = 0; i <= str_array.length; i ){
if(str_array[i]. match(/^s*extras/)){
……………………
}
}

Here, we pass in " /^s*extras/" will affect efficiency. It will construct a regular expression object with a temporary value of "/^s*extras/", execute the "match" method, and then destroy the temporary regular expression object. We can do this:
Listing 14. Using variables
Copy the code The code is as follows:

var sExpr = /^s*extras/;
for(var i = 0; i <= str_array.length; i ){
if(str_array[i].match( sExpr)){
……………………
}
}

This way there will be no temporary objects.
setTimeout and setInterval
The two functions "setTimeout" and "setInterval" can accept string variables, but they will cause performance problems similar to the "eval" mentioned before, so it is recommended to pass them in directly. the object itself.

Using early exit
Refer to the following two pieces of code:
Listing 15. Taking advantage of early exit
Copy code 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 judgment on "name.indexOf(...)", which causes the program to first execute the "indexOf" judgment every time it reaches this section, and then execute the subsequent "match" , on the premise that "indexOf" is much more efficient than "match", this will reduce the number of executions of "match", thus improving efficiency to a certain extent.
-------------------------------------------------- ----------------------------------
DOM operation performance tuning
The development of JavaScript is inseparable from DOM operations, so performance tuning of DOM operations is also very important in Web development.
Repaint and Reflow
Repaint is also called Redraw, which refers to a redrawing action that does not affect the structure and layout of the current DOM. The following actions will generate Repaint actions:
Invisible to visible (visibility style attribute)
Color or image changes (background, border-color, color style attributes)
Does not change the size, shape and position of page elements. But the change that changes its appearance
Reflow is a more significant change than Repaint. It mainly occurs when the DOM tree is manipulated. Any changes to the structure and layout of the DOM will generate Reflow. But when the Reflow operation of an element occurs, all its parent elements and child elements will release Reflow. In the end, Reflow will inevitably lead to the generation of Repaint. For example, the following actions will generate Repaint actions:

Changes in the browser window
Add and delete operations of DOM nodes
Some operations that change the size, shape and position of page elements Trigger
Reduce Reflow
From the introduction of Reflow and Repaint, we can know that each Reflow will consume more resources than its Repaint. We should try to reduce the occurrence of Reflow, or convert it to only trigger Repaint. The code for the operation.
Refer to the following code:
Listing 16. reflow introduction
Copy code The code is as follows:

var pDiv = document.createElement(“div”);
document.body.appendChild(pDiv);----- reflow
var cDiv1 = document.createElement(“ div");
var cDiv2 = document.createElement("div");
pDiv.appendChild(cDiv1);----- reflow
pDiv.appendChild(cDiv2);----- reflow

This is the code we often come into contact with, but this code will generate three reflows. Look at the following code again:
Listing 17. Reduce reflow
Copy the code The code is as follows:

var pDiv = document.createElement(“div”);
var cDiv1 = document.createElement(“div”);
var cDiv2 = document.createElement(“div”);
pDiv.appendChild(cDiv1);
pDiv.appendChild(cDiv2);
document.body.appendChild(pDiv);----- reflow

There is only one time here reflow, so we recommend this way of operating DOM nodes.
Regarding the above solution with less reflow operations, there is another pattern that you can refer to:
Listing 18. Using display to reduce reflow
Copy code 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 the pDiv first and then display it. In this way, the operation between hiding and displaying will not cause any reflow, which improves efficiency.

Special measurement attributes and methods
There are some special measurement attribute accesses and method calls in DOM elements that will also trigger Reflow. The typical ones are the "offsetWidth" attribute and the "getComputedStyle" method.
Figure 1. Special measurement attributes and methods

These measurement attributes and methods are roughly as follows:
Copy code The code is as follows:

offsetLeft
offsetTop
offsetHeight
offsetWidth
scrollTop/Left/Width/Height
clientTop/Left/Width/Height
getComputedStyle()
currentStyle(in IE))

Access and invocation of these properties and methods will trigger the generation of Reflow. We should minimize access to these properties and methods. and call, refer to the following code:
Listing 19. Special measurement attributes
Copy code 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 don’t have to access the “offsetWidth” attribute every time. This method is very suitable for loops and can greatly improve performance.

Style-related
We must often see the following code:
Listing 20. Style-related
Copy code The code is as follows:

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

But you can see that every style change here will generate Reflow. To reduce the occurrence of this situation, we can do this:
Solution 1:
Listing 21. className Solution
Copy code 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' ;

Using class instead of style can reduce the number of original Reflow or Repaints to one.

Solution 2:
Listing 22. cssText solution
Copy code 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.cssText = newStyle;

Set all styles at once, which also reduces Reflow Ways to improve performance.
XPath
A page often contains more than 1,000 page elements, and it often takes a certain amount of time to locate specific elements. If you use id or name to locate, the efficiency may not be too slow. If you use some other attributes of the element (such as className, etc.) to locate, the efficiency may not be ideal. Some may only be able to find the corresponding elements by traversing all elements (getElementsByTagName) and then filtering, which is even more inefficient. Here we recommend using XPath to find elements, which is a function supported by many browsers.
Listing 23. XPath solution
Copy the code The code is as follows:

if(document.evaluate){
var tblHeaders = document.evaluate(“//body/div/table//th”);
var result = tblHeaders.iterateNext();
while(result) {
result.style.border = “1px dotted blue”;
result ………………
result = xpathResult.iterateNext();
}
} else{ //getElementsByTagName() ……
// Handle the situation when the browser does not support XPath
……………………………………
}

The search engine of the browser XPath will optimize search efficiency and greatly shorten the result return time.

HTMLCollection object
This is a special type of object, they are a bit like arrays, but not exactly arrays. The return 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 results. They are the return values ​​of some special queries. In the following cases, they will re-execute the previous query and get new return values ​​(query results), although in most cases they will be the same as the previous one or several return values. :

Length attribute
A specific member
Therefore, the HTMLCollection object’s access to these attributes and members is much slower than that of an array. Of course there are exceptions. Opera and Safari handle this situation very well without much performance problems.
Refer to the following code:
Listing 24. HTMLConnection object
Copy code The code is as follows:

var items = [“test1”, “test2”, “test3”, ……………];
for(var i = 0; i < items.length; i ){
………………………………
}
var items = document.getElementsByTagName(“div”);
for(var i = 0; i < items.length; i ){
…………………………………………. .
}

The code at both ends above is more efficient than the one above. It is much slower, because each cycle will trigger "items.length", which will also cause the "document.getElementsByTagName(..)" method to be called again, which is why the efficiency will drop significantly. We can solve it like this:
Listing 25. HTMLConnection object solution
Copy code The code is as follows:

var items = document.getElementsByTagName(“div”);
var len = items.length
for(var i = 0; i < len; i ){
……………………………………………… .
}

In this way, the efficiency is basically the same as that of an ordinary array.
Dynamicly create script tags
It takes a certain amount of time to load and execute a JavaScript script. In our program, sometimes some JavaScript scripts are basically never used after being loaded (for example: the functions in the script have never been used called etc.). Loading these scripts will only take up CPU time and increase memory consumption, reducing the performance of your web application. Therefore, it is recommended to dynamically load JavaScript script files, especially those with a large content and high resource consumption.
Listing 26. Create script tag
Copy the code The code is as follows:

if(needXHR){
document.write(“
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template