JS optimization has been discussed a lot. Recently I have seen an article about aimingoo. Generally, the aimingoo statement is correct.
In addition to case studies like aimingoo, I would like to summarize the JS optimization principles in browser programming from a more general perspective.
First, unlike other languages, JS efficiency depends largely on JS engine efficiency. In addition to the advantages and disadvantages of engine implementation, the engine itself will also provide some specialCodeThe mode adopts some optimization strategies. For example, the JS engines of FF, opera, and Safari all perform special Optimization on the String concatenation operation (+. Obviously, to achieve maximum efficiency, you must understand the engine's temper and try to cater to the engine's taste. Therefore, the optimization of different engines is likely to be slow.
For cross-browser web programming, the biggest problem is IE6 (jscript 5.6 )! Without Hotfix, the garbage collection bug of the JScript engine may cause its performance in real applications to be different from that of other browsers. Therefore, in this case, optimization is actually done for JScript!
So the first principle isYou only need to optimize IE6 (unpatched JScript 5.6 or earlier)!
If yourProgramIt has been optimized to the acceptable performance in IE6, so there is basically no problem with the performance in other browsers.
Therefore, note that many of the problems I will discuss below may be completely different on other engines. For example, to concatenate strings in a loop, we usually think that array is needed. but the spidermonkey and other engines have optimized the "+" Operation of the string, and the result is array. instead, join is less efficient than directly using "+ "! However, if you consider IE6, the efficiency difference on other browser is not worth mentioning.
JS optimization is still the same as optimization in other languages. For example, it makes no sense not to rush to optimize it as soon as it comes up. The key to optimization is to focus on the most critical aspect, that is, the bottleneck. In general, bottlenecks always occur in large cycles. This is not to say that the Loop itself has a performance problem, but that the loop will quickly enlarge the possible performance problems.
So the second principle isLarge-scale cyclic objects are the primary optimization objects.
The following optimization principles make sense only in a large-scale loop. Such optimization outside the loop body is basically meaningless.
Currently, the vast majority of JS engines are interpreted and executed, while function calling is less efficient in all operations. In addition, a deep prototype inheritance chain or multi-level reference will also reduce the efficiency. In JScript, the overhead of level 10 references is roughly 1/2 of the overhead of an empty function call. The overhead of both is far greater than that of simple operations (such as the four arithmetic operations ).
So the third principle isAvoid excessive reference levels and unnecessary multiple method calls..
In some cases, attribute access is actually a method call. For example, all Dom attributes are actually methods. When traversing a nodelist, the loop condition for nodes. Length access seems to read the attribute, which is actually equivalent to the function call. In addition, in the implementation of IE Dom, childnodes. Length needs to be re-counted through internal traversal each time. (My God, but this is true! As I tested, the access time of childnodes. length is proportional to the value of childnodes. Length !) This is very expensive. Therefore, saving nodes. length to JS variables in advance can certainly improve the traversal performance.
Similarly, for function calls, the efficiency of user-defined functions is much lower than that of built-in functions, because the latter is the packaging of local engine methods, and the engine is usually C, C ++, written in Java. Furthermore, for the same function, the overhead of built-in language construction is usually higher than that of built-in function calling, because the former can be determined and optimized in the parse stage of JS Code.
So the fourth principle isTry to use the constructor and built-in functions of the language..
Here is an example of a high-performance string. Format method. String. the traditional format implementation method is string. replace (RegEx, func) is called N times when pattern contains N placeholders (including repeated. In this high-performance implementation, each format call only performs an array. join and then string. replace (RegEx, string) operations, both of which are built-in engine methods without any custom function calls. Two built-in method calls and N custom method calls are performance differences.
It is also a built-in feature, and the performance is still poor. For example, in JScript, the access performance to arguments is very poor, almost catching up with the callback function call. Therefore, if a simple function with a variable parameter becomes a performance bottleneck, you can make some internal changes. Instead of accessing arguments, you can handle it by explicitly determining the parameter.
Function Sum (){
VaR R = 0 ;
For ( VaR I = 0 ; I < Arguments. length; I ++ ){
R + = Arguments [I];
}
Return R;
}
This sum is usually called with a small number, and we hope to improve its performance when there are few parameters. If changed:
Code Function Sum (){
Switch (Arguments. Length ){
Case 1 : Return Arguments [ 0 ];
Case 2 : Return Arguments [ 0 ] + Arguments [ 1 ];
Case 3 : Return Arguments [ 0 ] + Arguments [ 1 ] + Arguments [ 2 ];
Case 4 : Return Arguments [ 0 ] + Arguments [ 1 ] + Arguments [ 2 ] + Arguments [ 3 ];
Default :
VaR R = 0 ;
For ( VaR I = 0 ; I < Arguments. length; I ++ ){
R + = Arguments [I];
}
Return R;
}
}
In fact, there will not be much improvement, but if it is changed:
Code Function Sum (a, B, c, d, e, f, g ){
VaR R = A ? B ? C ? D ? E ? F ? A + B + C + D + E + F: + B + C + D + E: + B + C + D: + B + C: + B:: 0 ;
If (G === Undefined) Return R;
For ( VaR I = 6 ; I < Arguments. length; I ++ ){
R + = Arguments [I];
}
Return R;
It will increase a lot (at least one time faster ).
The fifth principle is often the most important performance obstacle in real applications.Minimize unnecessary object Creation.
Creating objects has a certain cost, but this cost is not big. The most fundamental problem is that as JScript's stupid garbage collection scheduling algorithm increases the number of objects, severe performance degradation (according to Microsoft, complexity is O (n ^ 2 )).
For example, our common String concatenation problem, after my tests and verification, simply creating string objects multiple times is actually not the cause of poor performance. What's terrible is the unnecessary garbage collection overhead during object creation. The array. Join method does not create an intermediate String object, which reduces the overhead of garbage collection.
Therefore, if we can convert large-scale object creation into a single statement, its performance will be greatly improved! For example, by constructing the code and then eval -- in fact, the PIES project is working on a specialized large-scale object generator based on this idea ......
The preceding figure shows the five JS optimization principles.
In addition to these principles, there are also some special cases, such as Dom traversal, which will be discussed later.