In depth understanding of loop optimization in Javascript

  • 2020-03-26 23:45:50
  • OfStack

Loop is the basic function of most programming languages, and JS is no exception. The difference is that JS is an interpreted language, running in the browser environment, and the software and hardware conditions of the client side will have a great impact on the execution efficiency of JS. However, the client environment is unknown to developers, diverse, and difficult to change, so optimizing code quality is the main way to improve code efficiency.
In JS code, loops are a relatively common cause of performance problems. Understanding the nature of the loop and then making specific optimizations may lead to good performance gains.
For, while, do-while loop:
The three loops themselves have similar cycle efficiency, so you just need to choose according to the appropriate application scenario.
Take the for loop as an example:

var aValues = ["a", "b", "c", "d"];
for(var i = 0; i < aValues.length; i += 1){
 fDoSomethingA(aValues[i]);
 fDoSomethingA(aValues[i]);
}

In the above example, each loop compares the length of I with the length of the array, so it is necessary to re-read the array length each time. If the array length is unchanged in the loop, it is not necessary to do so. Instead of reading the length, we can use a local variable. Similarly, since aValues[I] is read more than twice in the example, we can also assign it to a local variable:

var aValues = ["a", "b", "c", "d"], nLength = aValues.length;
 for(var i = 0, sValue; i < nLength; i += 1){
 sValue = aValues[i];
 fDoSomethingA(sValue);
 fDoSomethingB(sValue);
 }

If the business logic of the loop is insensitive to the order of the loop, you can try the reverse loop, decreasing the counter to 0.

var aValues = ["a", "b", "c", "d"], nLength = aValues.length;
 for(var i = nLength, sValue; i -= 1;){
 sValue = aValues[i];
 fDoSomethingA(sValue);
 fDoSomethingB(sValue);
 }

In this way, the counter is compared with 0 by default, and even the local variable comparison is omitted, which theoretically improves efficiency.
The for - in cycle:
The for-in loop is more of an exhaustive loop, used to iterate over the properties of the object, and we know that the lookup of the properties of the object will continue to the top of the prototype chain, which greatly reduces the efficiency of the loop. There is little room for optimization in the way a for-in loop is written, and there is a rule to follow: try to use the for-in loop only when traversing a data-type object.
If the properties of the traversal object are explicit, an array loop can be used instead.
For example, traversing a contact object:

var aContact = ["N", "FN", "EMAIL;PREF", ...];
 for(var i = aContact.length; i -= 1;){
 fDoSomething(aContact[i]);
 }
 

Duff strategy
The main principle of the Duff strategy is to improve efficiency by reducing the number of cycles that are unrolled. For example,
A general cycle:

for(var i = aValues.length; i -= 1){
 fDoSomething(aValues[i]);
 }
 

If aValues. Length == N, it is more efficient to write the following:

fDoSomething(aValues[0]);
 fDoSomething(aValues[1]);
 fDoSomething(aValues[2]);
 fDoSomething(aValues[3]);
 ...
 ...
 fDoSomething(aValues[N-1]);

But if N is large, this is unrealistic, and the Duff strategy is a modest looping strategy.
Recently added the Duff policy to the netease email address book contacts initialization loop:

var nLength = aContacts.length,
//The total number of rounds
 nRounds = Math.floor( nLength / 8),
//Additional allowance
 nLeft = nLength % 8,
i = 0;
//Let's do the margin first
 if(nLeft){
 do{
 fFormat(aContacts[i ++]);
 }while(-- nLeft)
}
//Format 8 times per round
 if(nRounds){
 do{
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 fFormat(aContacts[i ++]);
 }while(-- nRounds)
 }

As shown above, each round of the loop can perform the formatting of eight contact data, and there is one round to process the remaining contacts. Thus, in the case of more contacts, the total number of cycles is greatly reduced, which can reduce the consumption of cycles. In addition, 8 is the optimal value proposed by the Duff policy.
In actual testing, it was found that the performance improvement in Internet explorer was more than 10-20%, and the difference was almost invisible in non-internet explorer.
Conclusion: in the process of testing, it was found that the efficiency gap between the optimized and pre-optimized non-ie browsers was not very large, or even negligible, which indicates that the JS engine of these browsers was correct

Related articles: