Algorithm and process control
- The overall structure of the code is one of the main factors affecting speed.
- Less code doesn’t mean faster, it just looks cleaner.
- The organizational structure of the code and the way to solve specific problems are the main factors that affect the performance of the code
cycle
Looping is a common programming pattern and a key focus for improving performance
Type of loop
Four types of loops
- The for loop
- While loop The while loop is the simplest pretest loop
- The do-while loop is the only post-test loop in JavaScript that consists of two parts, the body of the loop and the post-test condition. It will run at least once
var i = 0;
do {
// Loop body
} while ( i++ < 10 )
Copy the code
- A for-in loop can enumerate the property names of any object
for (var prop in object) {
// Loop body
}
Copy the code
Cycle performance
Of the four loops, the for-In loop is significantly slower than the others because each iteration searches for instance or stereotype attributes simultaneously, and for the same number of iterations, the for-In loop ends up being 1/7 of the speed of the other types
Reduce iteration workload
To reduce iteration effort, a good way to increase the overall speed of a loop is to limit the number of time-consuming operations in the loop
Example:
for (var i = 0; i < items.length; i++) {
process(items[i])
}
Copy the code
In the for loop above, each time the body of the loop is run, the following action is generated:
- Find the property once in the control condition (Items.length)
- Compare values once in the control condition (I < items.length)
- A comparison operation to see if the control condition evaluates to true (I < items.length == true)
- An increment operation (i++)
- An array lookup (Items [I])
- A function call (process(items[I]))
Optimization solution 1: Reduce The Times of querying items. Length
Example:
for (var i = 0, len = items.length; i < len; i++) {
process(items[i])
}
Copy the code
Optimization scheme 2: reverse order search. In general, the order of the items is independent of the task to be performed, so you can use a reverse loop to evaluate the performance of each control condition by simply comparing it to 0. Is this true? –> a comparison (true?)
Example:
for(var i = items.length; i--;) {
process(items[i])
}
Copy the code
Operation process:
- Comparison in one control condition (I == true)
- One subtraction operation (I –)
- An array lookup (Items [I])
- A function call (process(items[I]))
prompt
When the cycle complexity is O(n), reducing the amount of work per iteration is the most effective method. When the complexity is greater than O(n), the number of iterations is reduced
Reduce the number of iterations — Duff devices
Duff’s Device is a mode that limits the number of iterations of a loop. Whether a Duff Device should be used depends largely on the number of iterations
Template code:
var i = items.length % n; // Loop the remainder first
while(i){
process(items[i--]);
}
i = Math.floor(items.length / n); // The loop body is 8 times the normal loop and can be written as a function call
while(i){
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
process(items[i--]);
}
Copy the code
Efficiency test code:
var arr = [], times = 10000000, times2 = 10000000;
for (var i = 1; i <= times; i++) {
arr[i] = i ;
}
console.time('pre')
var sum = 0;
for (var i = 1; i <= times; i++) {
sum += (1 / arr[i]);
}
console.log(sum)
console.timeEnd('pre')
console.log('* * * * * * * * * * * * * * * * * * * * * * * *')
// Duff device
console.time('last')
var all = 0;
var len = times / 8, startAt = times % 8;
do {
switch(startAt) {
case 0: all += (1 / arr[times--]);
case 1: all += (1 / arr[times--]);
case 2: all += (1 / arr[times--]);
case 3: all += (1 / arr[times--]);
case 4: all += (1 / arr[times--]);
case 5: all += (1 / arr[times--]);
case 6: all += (1 / arr[times--]);
case 7: all += (1/ arr[times--]); }}while (--len)
console.log(all)
console.timeEnd('last')
// A normal while loop
console.time('last2')
var sumall = 0;
while(times2) {
sumall += (1 / arr[times2--]);
}
console.log(sumall)
console.timeEnd('last2')
Copy the code
prompt
Modern browser engines have actually been optimized several times, and when the efficiency test code above runs around 1000 times, the for loop and the while loop and the Duff device run just as fast
Here’s how many times it was executed:
chrome
In Chrome, the while loop and the Duff device are significantly faster than the for loop, but the while loop and the Duff device are about the same in time, and the Duff device may even be shorter than the while loop
While > Duff device > for loop
Test 1:
Test 2:
Test 3:
IE
In Internet Explorer, the dash device is more efficient, and the for loop is less efficient than the while loop
Duff device > while > for loop
Test 1:
Test 2:
Test 3:
FireFox
It’s also similar to Internet Explorer in Firefox
Duff device > while > for loop
Test 1:
Test 2:
Test 3
Function-based iteration
Function-based iteration: forEach()
ForEach iterates through all the members of an array and executes a function
However, in all cases, loop based iteration is 8 times faster than function based iteration. Loop based iteration takes precedence over function based iteration when speed requirements are strict and function based iteration is not an appropriate choice when performance is strictly required
Conditional statements
In JavaScript, conditional statements are mainly if-else and switch
The larger the number of conditional judgments, the more likely it is to use switch statements, mainly for the sake of legibility of the code
In most cases, switch is faster than if-else. But it’s only obvious if the number of conditions is large
If-else statements can be considered split into nested if-else statements to minimize the number of conditional judgments, such as dichotomy
recursive
Recursion is the ability to make complex algorithms simpler, such as factorial functions:
function factorial(n) {
if (n == 0) {
return 1
} else {
return n * factorial(n - 1)}}Copy the code
Disadvantages of recursion
① : The potential problem with recursive functions is that unclear or lack of termination conditions will cause the function to run for a long time, that is, may produce infinite recursive calls, the user interface is suspended.
Recursive functions may also encounter browser “call stack size limits”.
Call stack limit
The number of recursions supported by the JavaScript engine is directly related to the size of the JavaScript call stack.
Internet Explorer’s call stack is related to system memory. All other browsers have a fixed number of call stack sizes
If you encounter call stack limitations, the first step should be to examine the recursive instances in your code
Recursive model
There are two types of recursion patterns worth noting. One is the “direct recursion pattern,” the factorial call written above, which is easy to detect when something goes wrong. The other is the “hidden mode”, where two functions call each other in an infinite loop, and errors in this mode are difficult to locate examples:
function first() { second() }
function second() { first() }
first();
Copy the code
The iteration
Any algorithm that can be implemented recursively can also be implemented iteratively.
Iterative algorithms usually consist of several different loops, which can improve performance by replacing long-running functions with optimized loops.
Running a loop is much less expensive than calling a function repeatedly
Iterative implementation of recursive algorithm is one of the ways to avoid stack overflow errors
Memoization
Reducing effort is the best performance optimization technique
Doing the same task more than once is simply a waste of time, and Memoization is a way to avoid redoing it.
For example, the previous common factorial recursion was improved with Memoization and greatly improved efficiency:
function memfactorial(n) {
// Set the original memfactorial.cache
if(! memfactorial.cache) { memfactorial.cache = {"0": 1."1": 1}}Memfactorial. Cache [n] = memfactorial. memfactorial.cache[n]
if(! memfactorial.cache.hasOwnProperty(n)) { memfactorial.cache[n] = n * memfactorial(n -1);
}
return memfactorial.cache[n];
}
Copy the code
Test efficiency:
console.time('Ordinary recursion')
var six = factorial(16)
console.timeEnd('Ordinary recursion')
console.time('Memoization')
var one = factorial(16)
console.timeEnd('Memoization')
Copy the code
It is also possible to encapsulate Memoization as a base function memoize() note: This generic Memoization method is less effective than manually updated algorithms and is best implemented manually
function memoize(fundamental, cache) {
cache = cache || {};
var shell = function(arg) {
if(! cache.hasOwnProperty(arg)) { cache[arg] = fundamental(arg); }return cache[arg]
}
return shell;
}
Copy the code
Call generic functions:
var memfactorial = memoize(factorial)
memfactorial(16)
Copy the code
section
1. Avoid for-in loops
The number of times to query items. Length can be reduced, and there is no strict order, can use reverse order search, reduce the number of operations
Point 3 to optimize when writing code: Consider Memoization to avoid double-counting when encountering stack overflows