JavaScript Best Practices — Performance

John Au-Yeung - Jan 26 '21 - - Dev Community

Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62

Subscribe to my email list now at http://jauyeung.net/subscribe/

Like any other programming language, JavaScript has its own list of best practices to make programs easier to read and maintain. There are a lot of tricky parts to JavaScript, so there are things we should avoid that reduce the quality of our code. By following best practices, we can create elegant and manageable code that’s easy for anyone to work with.

In this article, we’ll look at ways to improve the performance of our apps. Actions include caching data in variables, using the fastest way to loop through variables, reducing DOM access and elements on the page, and deferring script loading.

Reduce Access to Variables and Properties

We should reduce the times that we access variables and object properties in our apps.

This is because every time we do this, the CPU has to access the item in memory again and again to compute its results.

Therefore, we should do this as little as possible.

For example, if we have a loop, we shouldn’t write the following:

for (let i = 0; i < arr.length; i++) {

}
Enter fullscreen mode Exit fullscreen mode

Instead, we should write:

let length = arr.length;
for (let i = 0; i < length; i++) {

}
Enter fullscreen mode Exit fullscreen mode

This way, arr.length is only referenced once in our loop instead of accessing it in every iteration.

Fastest Way to Loop Through Variables

In JavaScript, there’re multiple ways to iterate through iterable objects. One is the good old for loop. Other ways include the for...of loop, the forEach method for arrays. map and filter also loop through the array as the map and filter operations are being done. There’s also the while loop.

Of all the ways to run loops, the for loop is the fastest way, with or without caching the length like we did above. Caching the length sometimes makes the loop performs better, however.

Some browser engines have optimized the for loop without caching the length property.

The while loop with decrementing index is approximately 1.5 times slower than the for loop

Using the forEach loop is 10 times slower than the for loop, so it’s probably better to avoid it, especially for large arrays.

We can see the results here.

Reduce DOM Access

Accessing the DOM is an expensive operation since the browser has to grab the element from the web page and then create an object from it and return it.

To reduce DOM access, we should set the DOM Node objects to a variable if we need to manipulate it more than once.

For example, if we have the following HTML and we want to set some text to it after a few seconds:

<p id='foo'>

</p>
Enter fullscreen mode Exit fullscreen mode

We can write the following code to do so:

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');
})();
Enter fullscreen mode Exit fullscreen mode

In the code above, we have one function which gets the HTML element that we want to manipulate, and the text content that we want to set.

The setText function returns a promise to set the text to a given element after 3 seconds.

Then we have an async function to set the text 3 times. The important part is that we pass in the reference to the element in each call. This way we don’t have to get the element from the web page 3 times, which is an expensive operation.

Photo by Sawyer Bengtson on Unsplash

Reduce DOM Size

Rendering the DOM tree is slow. Therefore, we have to reduce the size of the tree.

There’s no way around it but to make our web pages as simple as possible.

Having a smaller DOM make searching for elements with methods like querySelector, getElementById, or getElementsByTagName faster since there’s less to look for.

Also, page rendering performance will improve since there’s less to load. This is especially true for slower devices like phones and tablets.

Don’t Declare Unnecessary Variables

Every time we declare variables, the browser has to reserve memory space for the variables. Therefore, to reduce memory usage, we should declare too many variables.

For example, if we have the following HTML:

<div id='foo'>
  <p>

  </p>
</div>
Enter fullscreen mode Exit fullscreen mode

And we want to set the text content of the p element, we shouldn’t write something like:

const foo = document.querySelector('#foo');
const p = foo.querySelector('p');
p.textContent = 'foo';
Enter fullscreen mode Exit fullscreen mode

since we have 2 variables. This means our computer has to store the values for 2 more JavaScript variables.

Instead, we can reduce to no variable declarations by writing:

document.querySelector('#foo p').textContent = 'foo';
Enter fullscreen mode Exit fullscreen mode

As we can see, we can use the querySelector method to select anything with CSS selectors. This means that we should use this method and the related querySelectorAll method to select elements since they can both use CSS selectors to select any HTML element node.

Defer the Loading of Scripts

Loading JavaScript files is an expensive operation. The browser has to download the file, parse the content, and then convert it to machine code and run it.

The browser will download one file at a timeline by line, so it’ll hold up any other operation from happening.

Therefore, we should delay it as much as we can. We can do this by putting the script tag to the end. Also, we can use the defer attribute on the script tag to do this.

Also, we can run scripts after the page is loaded by create script elements on the fly and appending it 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);
};
Enter fullscreen mode Exit fullscreen mode

Anything that can be loaded after the page loads can use this method of script loading.

We can speed up our pages by doing a few things. First, we can cache data in variables so we don’t have to access them repeatedly. Then we can loop through items faster with the for loop.

Also, we can reduce the DOM size to reduce the items that need to be loaded. We can also cache DOM objects in our code by assigning them to variables.

We also should not declare unnecessary variables, and we should defer the loading of scripts as much as possible so it won’t hold up our browser.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .