This article is translated from JavaScript Best Practices — Performance by John Au-Yeung
Like any other programming language, JavaScript has its own list of best practices to make programs easier to read and maintain. JavaScript has a lot of tricky parts, so you should avoid some practices that degrade your code. By following best practices, we can create elegant and manageable code that anyone can easily use.
In this article, we’ll explore ways to improve application performance, including caching data in variables, looping through variables using the fastest method, reducing DOM access and elements on the page, and delaying script loading.
Reduce access to variables and attributes
We should reduce the number of times we access variables and object properties in our application.
This is because each time this operation is performed, the CPU must access the item in memory again and again to calculate its results.
Therefore, we should do this as little as possible.
For example, a loop should not look like this:
for(let i = 0; i < arr.length; i++) {
}
Copy the code
Instead, it should be written:
let length = arr.length;
for (let i = 0; i < length; i++) {
}
Copy the code
In this way, arr.length is referenced only once in our loop, rather than being accessed in each iteration.
The fastest way to loop over a variable
In JavaScript, there are several ways to iterate over an iterable. One is the old for loop, other methods include for… Of loop, forEach method of array. The map and filter operations also iterate over groups of numbers. Then there’s the while loop.
Of all the ways to run a loop, the for loop is the fastest, whether or not length is cached as above. However, cache length can sometimes make the loop perform better.
Some browser engines optimize for loops without caching the Length attribute.
The decrement index whil e loop is about 1.5 times slower than the for loop.
The forEach loop is 10 times slower than the for loop, so it’s best to avoid it, especially for large arrays.
We can see the results here.
Reducing DOM access
Accessing the DOM is an expensive operation because the browser must take the element from the web page, then create an object from it and return it.
To reduce DOM access, if we need to manipulate the DOM Node object multiple times, we should assign it to the variable.
For example, if we have the following HTML and want to set some text to it after a few seconds:
<p id='foo'>
</p>
Copy the code
We can write the following code to do this:
const setText = (element, textContent) => {
return new Promise((resolve) => {
setTimeout(() => {
element.textContent = textContent;
resolve();
}, 3000)
})
}
(async () => {
const foo = document.querySelector('#foo');
await setText(foo, 'foo');
await setText(foo, 'bar');
await setText(foo, 'baz'); }) ();Copy the code
In the above code, we have a function to get the HTML element we want to manipulate and the text content we want to set.
The setText function returns a Promise and sets the text to the given element after 3 seconds.
Then we have an async function to set the text 3 times. The core part is that we pass it a reference to the element every time we call it. This way, we don’t have to fetch elements from a web page every time, which is an expensive operation.
Reduce DOM size
DOM trees are slow to render. Therefore, we must reduce the size of the tree.
There is no choice but to keep our web pages as simple as possible.
When DOM is small, you can search for elements faster using methods like querySelector, getElementById, or getElementsByTagName because there is less to look for.
In addition, page rendering performance is improved because less content is loaded. This is especially true for slower devices like phones and tablets.
Don’t declare unnecessary variables
Every time we declare a variable, the browser must allocate storage space for the variable. Therefore, to reduce memory usage, we should not declare too many variables.
For example, if we have the following HTML:
<div id='foo'>
<p>
</p>
</div>
Copy the code
We want to set the text content of the P element, we should not say:
const foo = document.querySelector('#foo');
const p = foo.querySelector('p');
p.textContent = 'foo';
Copy the code
Because we have two variables here, this means that our computer has to store the values of two additional JavaScript variables.
We can reduce variable declarations by writing the following code:
document.querySelector('#foo p').textContent = 'foo';
Copy the code
As we have seen, we can use the querySelector method to select anything through the CSS selector. This means we should use this method and the related querySelectorAll method to select elements, since both can use CSS selectors to select any HTML element node.
Loading a JavaScript file is an expensive operation. The browser must download the file, parse the contents, and then turn it into machine code and run it.
The browser downloads a file and blocks anything else.
Therefore, we should delay it as long as possible. We can do this by putting the script tag at the end. Alternatively, we can do this using the defer attribute on the script tag.
Alternatively, we can dynamically create a script element after the page loads and run the script as follows:
window.onload = () => {
const element = document.createElement("script");
element.src = "https://code.jquery.com/jquery-1.12.4.min.js";
document.body.appendChild(element);
};
Copy the code
After the page loads, you can use this script’s loading method to load anything you want.
summary
There are a few things we can do to speed up our pages. First, we can cache data in variables, so we don’t have to access them repeatedly. We can then use the for loop to iterate through the project more quickly.
Alternatively, we can reduce the DOM size to reduce the number of items that need to be loaded. We can also cache DOM objects in our code by assigning them to variables.
We should also not declare unnecessary variables, and we should delay the loading of the script as long as possible to avoid jamming our browser.