JavaScript performance tuning _javascript techniques for Web performance optimization

Source: Internet
Author: User
Tags eval setinterval xpath
JavaScript is a relatively complete front-end development language, in today's web development applications are very wide, 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 that there will be more and more in the future. JavaScript, as a language to interpret execution, and its single-threaded mechanism, determines that performance issues are a soft spot for JavaScript and a problem that Web software engineers need to attach great importance to in writing JavaScript, especially for Web 2.0 applications. Most web software engineers have more or less experienced poor performance problems with the Web 2.0 applications they have developed, mainly because of the lack of JavaScript performance and overloading of browsers. However, it is not easy to solve the performance problems of this kind of interpretation execution and single-threaded operating language. This article will highlight some tips and best practices for developing JavaScript performance tuning, as well as some of the ways in which JavaScript operates on the performance tuning of DOM nodes.

Brief 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, and a large part of the performance problems of Web applications are caused by the poor performance of JavaScript scripts written by programmers, including the performance problems of the JavaScript language itself, and the DOM Performance issues when interacting. 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
JavaScript language because of its single-threaded and interpretation of the implementation of the two characteristics, it determines that it has a lot of local performance problems, so there are many improvements can be.

Question of Eval
Compare the following code:
Listing 1. Question of Eval
Copy Code code as follows:

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

The "eval" code is 100 times times slower than the "eval" code.
The main reasons are: JavaScript code performs a "precompiled" operation before execution: first, it creates an active object in the current execution environment and sets those variables declared with Var to the properties of the active object, but at this point the variables are assigned to undefined, and those values are Function-defined functions are also added as properties of the active object, and their value is precisely the definition of the function. However, if you use "eval", the Code in eval (which is actually a string) cannot be identified in advance and cannot be resolved and optimized in advance, that is, the precompiled operation cannot be performed. Therefore, its performance will also be greatly reduced.

Use of Function
Compare the following code:
Listing 2. Use of function
Copy Code code 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 previous "eval" method, where the "func1" efficiency is much less efficient than "FUNC2", so it is recommended that the second approach be used.

Scope Chain of the function (scope):
The JavaScript code interprets execution, and when it goes inside the function, it analyzes the current variables in advance, and the variables are grouped into different levels (level), typically:
Local variables are placed at level 1 (shallow) and global variables are placed at Level 2 (deep). If you enter a "with" or "Try–catch" code block, the new hierarchy is added, the variables in "with" or "catch" are placed in the shallow layer (layer 1), and the previous levels are deepened in turn.
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", "combination" belong to local variables, in layer 1. "Document", "MyObj" belongs to the global variable, in Layer 2.
The lower the level of the variable, the faster the access (read or modify), the deeper the layer, the slower the access speed. So here the "images", "widget", "combination" access speed than "document", "MyObj" to a bit faster. Therefore, the recommended use of local variables, the following code can be seen:
Listing 4. Using Local variables
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));
}
MyObj.container.property1 = combination[0];
MyObj.container.property2 = Combination[combination.length-1];
}

We replace the global variable "document" with the local variable "Doc", which can improve performance, especially in functions that use global variables in large quantities.
Look at the following code:
Listing 5. With caution
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 this performance will be affected. As previously said, when we enter the "with" code block, "combination" from the original Layer 1 to Layer 2, so that the efficiency will be greatly compromised. So compare, or use the original code:
listing 6. Improved 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));
}
MyObj.container.property1 = combination[0];
MyObj.container.property2 = Combination[combination.length-1];
}

But this is not the best way, JavaScript has a feature, for object objects, its property access level deeper, the less efficient, such as the "MyObj" has visited the 3rd floor, we can improve this:
Listing 7. Narrowing the object access level
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));
}
var ctn = Myobj.container;
Ctn.property1 = combination[0];
Ctn.property2 = Combination[combination.length-1];
}

We use local variables to replace the "container" object of the 2nd layer of "myobj". If you have a large number of this access to the object's deep properties, you can improve performance by referencing the above methods.

string (strings) Related
string concatenation
Often see this code:
Listing 8. Simple concatenation of strings
Copy Code code as follows:

STR + + "str1" + "str2"

This is a common way for us to stitch strings, but there are some temporary variables created and destroyed that affect performance, so it is recommended to stitch in the following ways:
listing 9. String array mode concatenation
Copy Code code 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 implement concatenation of strings, especially when running on the old version of Internet Explore (IE6) of the program, there is a very noticeable performance improvement.
Of course, the latest browsers (such as Firefox firefox3+,ie8+, and so on) have optimized the concatenation of strings, and we can write this:
listing 10. Fast string concatenation
Copy Code code as follows:

str = "STR1"
str = "STR2"

The new browser optimizes "+ +" and performs slightly faster than the "join" method of the array. Newer versions of browsers in the near future may also be optimized for "+", so we can write directly at that time: str = "str1" + "str2".

implicit-type conversions
Refer to the following code:
listing 11. Implicit Type Conversions
Copy Code code 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 each loop, but since we assign the constant "12345678" to "str", "str" is actually not a string object, and when it calls the "charAt" function, it temporarily constructs a value of " 12345678 string object, and then call the "CharAt" method and finally release the string temporary object. We can make some improvements:
listing 12. Avoidance of 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));
}

Thus, the variable "str" as a string object, there will be no such implicit type conversion process, so that the efficiency will be significantly improved.

String Matching
JavaScript has a RegExp object that supports regular expression matching for strings. is a good tool, but its performance is not very ideal. In contrast, some of the basic methods of string object (string) itself are very efficient, such as "substring", "indexOf", "charAt", and so on, and when we need to match a string with a regular expression, we can consider:
Whether you can solve the problem through the basic methods supported by the string object itself.
Whether you can narrow the range of regular expressions by using "substring".
These methods can effectively improve the efficiency of the program.
With regard to regular expression objects, it is also important to note that the following code is referenced:
listing 13. Regular Expressions
Copy Code code 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 can affect efficiency, it builds a regular expression object with a temporary value of "/^s*extra\s/", executes the "match" method, and then destroys the temporary regular expression object. We can do this:
listing 14. Using Variables
Copy Code code as follows:

var sexpr =/^s*extra\s/;
for (var i = 0; I <= str_array.length; i++) {
if (Str_array[i].match (sexpr)) {
........................
}
}

So there will be no temporary objects.
SetTimeout and SetInterval
These two functions, "settimeout" and "setinterval", can accept string variables, but will bring performance problems similar to those mentioned earlier, so it is advisable to pass on the function object itself.

Use early exit
Refer to the following two paragraph code:
listing 15. Using Early exit
Copy Code code 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 one more pair of "name.indexof (...)" 's judgment, this allows the program each time to go to this section will first execute the "indexOf" judgment, and then execute the "match", in "IndexOf" than "match" efficiency is much higher than the premise, this will reduce the "match" the number of executions, thus a certain degree of improvement in efficiency.
--------------------------------------------------------------------------------
DOM Operations Performance Tuning
The development of JavaScript is inseparable from the operation of DOM, so the 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 produce Repaint actions:
Invisible visible (visibility style properties)
Color or picture changes (background, border-color, color style properties)
Do not change the page element size, shape and position, but change its appearance
Reflow is a much more significant change than the Repaint. It mainly occurs when the DOM tree is manipulated, and any change in the structure and layout of the DOM will result in reflow. However, when an element's reflow operation occurs, all its parent elements and child elements will be released Reflow, and finally reflow will inevitably lead to Repaint generation. For example, the following action produces a Repaint action:

changes to the browser window
Add-delete operations for DOM nodes
Triggers for actions that change the size, shape, and position of page elements
Reduce reflow
The introduction of Reflow and Repaint shows that each time the reflow brings more resource consumption than its Repaint, we should minimize the occurrence of reflow or turn it into code that triggers only the Repaint operation.
Refer to the following code:
Introduction to the list of reflow
Copy Code code 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 that we often contact, but this code produces 3 times reflow. Look at the following code:
listing 17. Reduction of Reflow
Copy Code code 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's only one reflow here, so we recommend how this DOM node operates.
For solutions to the less reflow operations described above, there is also a model to refer to:
listing 18, using display to reduce reflow
Copy Code code 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, then show, so that the operation between hiding and display will not produce any reflow, improve the efficiency

Special measurement properties and methods
The DOM element has some special measurement properties of the access and method of the call, will also trigger reflow, the more typical is the "offsetwidth" property and "getComputedStyle" method.
Figure 1. Special measurement properties and methods

These measurements have roughly these properties and methods:
Copy Code code as follows:

Offsetleft
offsettop
Offsetheight
Offsetwidth
Scrolltop/left/width/height
Clienttop/left/width/height
getComputedStyle ()
Currentstyle (in IE))

The access and invocation of these properties and methods will trigger the generation of reflow, and we should minimize access to and invocation of these properties and methods, referring to the following code:
listing 19. Special Measurement Properties
Copy Code code 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 cache the value of "offsetwidth" with a temporary variable so that we do not have to access the "offsetwidth" property every time. This approach works well in loops and can greatly improve performance.

Style related
We must often see the following code:
listing 20. Style related
Copy Code code 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 as you can see, every change in the style here will produce reflow. Need to reduce the occurrence of this situation, we can do this:
Solution 1
List of ClassName solutions
Copy Code code as follows:

. Class1 {
border: ' 1px solid red '
Background-color: ' Silver '
padding: ' 2px 3px '
Margin-left: ' 5px '
}
document.getElementById ("Pos_element"). ClassName = ' Class1 ';

Instead of style with class, you can reduce the number of reflow or Repaint that you originally had to one.

Solution 2
List of Csstext solutions
Copy Code code 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;

Setting all styles at once is also a way to reduce reflow performance.
Xpath
A page often contains more than 1000 page elements, in the positioning of specific elements, often need a certain amount of time. If you use ID or name positioning may not be too slow, if you use some of the elements of other attributes (such as className, etc.) positioning, may be inefficient. Some may only be able to navigate through all the elements (getElementsByTagName) and then filter to find the appropriate element, which is even less effective, where we recommend using XPath to find elements, which are supported by many browsers themselves.
Listing 23. XPath Solutions
Copy Code code 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 () ...
Processing browsers do not support XPath
....................................
}

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

Htmlcollection Objects
This is a special kind of object, which is a bit like an array, but not exactly an array. 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 result. They are the return values of some of the more specific queries, which, in the following cases, rerun the previous query and get a new return value (the query result), although in most cases the same as the previous or several return values:

Length Property
A specific member of the
Therefore, the Htmlcollection object's access to these properties and members is much slower than the array. Of course, there are exceptions, Opera and Safari deal with this situation very well, not too much performance problems.
Refer to the following code:
Listing 24. Htmlconnection Objects
Copy Code code 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 above two ends of the code, the efficiency of the following is much slower than the above paragraph, because each cycle will have a "items.length" trigger, it will lead to "document.getElementsByTagName (..)" method, which is the reason why the efficiency will be greatly reduced. We can solve this:
listing 25. Htmlconnection Object Solution
Copy Code code 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 the normal array.
Create a script label dynamically
It takes a while to load and execute a JavaScript script, and in our program, some JavaScript scripts are sometimes loaded and have not been used (for example, the functions in a script have never been invoked, etc.). Loading these scripts can only consume CPU time and increase memory consumption, reducing the performance of WEB applications. So it is recommended to dynamically load JavaScript script files, especially those that have more content and consume larger resources.
Listing 26. Create a script label
Copy Code code as follows:

if (NEEDXHR) {
document.write ("<script type= ' test\/javascript ' src= ' dojo_xhr.js ' >");
}
if (Dojo.isie) {
document.write ("<script type= ' test\/javascript ' src= ' vml.js ' >");
}

--------------------------------------------------------------------------------
Concluding remarks
This article introduces some of the small details about performance in web development, starting with JavaScript itself, and introducing the use and programming rules of some functions that need to be avoided in JavaScript, such as the drawbacks of eval, function scope chain, and St Ring usage, etc., also shares some of the more recommended practices and extends to JavaScript's performance tuning of DOM operations, such as using Repaint and reflow mechanisms, how to use special measurement attributes, style-related performance tuning, and Htmlcollection objects The principle and use of small tips. These small details can be noticed in the development process as much as possible to improve the performance of our WEB applications.
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.