Optimize JavaScript Performance in Web Applications: Strategies and Best Practices
Table of contents
- 1. Order in which elements are loaded
- 2. Minify JavaScript code for smaller file sizes
- 3. Optimize Javascript with minification
- 4. Asynchronous loading of JavaScript: Defer and Async tags
- 5. Exclude unused components of .js libraries
- 6. Use the HTTP/2 protocol
- 7. Position CSS and JavaScript code in <head>
- 8. Where you can, use CSS3 effects in place of JavaScript
- 9. Memory leaks
- 10. Limit variable calls
- 11. Reduce DOM and access size
- 12. Code splitting
- 13. Use Web Workers
- Conclusion
JavaScript is a great front-end programming tool that you can use to create interactive, feature-rich websites and fast, seamless web applications.
JavaScript or JS helps you implement complex things on your website.
Many developers know the importance of minified JavaScript files, but few know about optimized JavaScript code.
Optimized code is a combination of intelligently programmed logic and small hacks to optimize performance and speed and save you time.
Poorly written JavaScript code can slow down your website and negatively impact load and display speeds.
This article introduces some tools that can help you optimize JavaScript performance.
1. Order in which elements are loaded
First, all elements in the section must be preloaded before the visitor can see anything in the browser.
Then all subsequent element loads are arranged logically.
JavaScript within sections can slow down page rendering.
When an unoptimized page loads, users may see a “white screen” before the entire page loads.
Optimized page loading (actual rendering) occurs gradually, allowing users to view content gradually until the page is fully loaded.
2. Minify JavaScript code for smaller file sizes
Minifying code is not the same as hiding code, but both are methods of transforming JavaScript to make it harder to read or smaller.
The latter is achieved through minification, which reduces file size and speeds up page load times.
Line breaks, extra spaces, comments, etc.
- These all increase the size of JavaScript files and affect page load speed.
Compressing the code solves this problem nicely.
Machines are not as sensitive to the visual style of code as humans.
Even if all the JavaScript code fits into one string, the computer can still read and launch the minified code.
3. Optimize Javascript with minification
Optimization is a special type of JavaScript minification.
This type of minimizer not only removes unnecessary spaces, commas, comments, etc.
,but also helps avoid “dead code”:
• Google Closure Compiler
• UglifyJS
• Microsoft AJAX Minifier
How does optimization work? Here’s an example:
Before optimization:
function test(node) {
var parent = node.parentNode;
if (0) {
alert( "Hello from the other side" );
} else {
alert( "We love JavaScript" );
}
return;
alert( 1 );
}
After optimization:
function test(){alert("We love JavaScript")}
What exactly did optimization accomplish?
1. The variable parent will never need to be used, so it gets deleted;
2. False if() {…} is deleted as ‘dead code’; true else leaves only one possibility.
3. Return is deleted; it’s also dead code.
4. Asynchronous loading of JavaScript: Defer and Async tags
Asynchronous loading of JavaScript is a type of sync loading. It means that your website loads in a multi-streamed way.
When the browser finds the string with <script src="some.js"></script>
, it will stop the creation of DOM and CSSOM models while the JavaScript is executed. This is why most JavaScript code is located after the main HTML code.
To understand this point a little better, take a look at this code:
<html>
<head>
<script src="big.js"></script>
</head>
<body>
This text will not be present until big.js is loaded.
</body>
</html>
Instead, you can add an async tag to the JavaScript so that creation of the DOM model happens in parallel, and won’t be interrupted while the JavaScript is loading and executed.
Use caution if your JavaScript must make some manipulations to the HTML or CSS, or if you’re loading a script in a strong order (e.g., jQuery-dependent libraries).
5. Exclude unused components of .js libraries
Most developers use libraries like jQuery UI or jQuery Mobile as is. This means that the code includes all possible components of each library, when you may only need two or three. A similar situation occurs with other JavaScript libraries as well. If you can manage what components will be included in your package of library, definitely do it. Your website will load much faster, and your visitors will get a better experience.
Visit the Download builder of jQuery Mobile or jQuery UI to create your own package of those libraries.
6. Use the HTTP/2 protocol
This second, encrypted version of the main Internet protocol can provide you with a lot of cool features, including the asynchronous download of external files, most notably JavaScript. While HTTP requires deep learning and an advanced knowledge of JavaScript theory, HTTP/2 can make JavaScript load faster.
Use httpsvshttps.com to get your own experience with HTTPS and HTTP/2. Another one test is Aka`mai HTTP/2 demo.
7. Position CSS and JavaScript code in <head>
This technique helps your page load faster but requires pretty good knowledge of DOM and SCCOM. The idea is to bring a minimum amount of CSS and JavaScript code to the <head></head>
section so it loads it immediately, while the more extensive code is stored in separate .css and .js files, like usual.
8. Where you can, use CSS3 effects in place of JavaScript
Older versions of CSS like 1.0 or 2.0 were not as powerful on their own and required a bit more JavaScript to create more advanced styling effects. But CSS 3.0 is a very capable language on its own, with lots of added functionality that requires less JavaScript. Another benefit is that CSS can be pre-compiled so CPU usage for CSS is lower than JavaScript.
For example, you can add sliders like CSSSlider in CSS3 and HTML5 without any JavaScript at all like. Here’s another free one to try:
HTML:
<!DOCTYPE html>
<html lang="en"></html>
<head>
</head>
<meta charset="UTF-8">
<title>CSS Slider</title>
<body></body>
<base href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/">
<div id="slider"></div>
<figure></figure>
<img src="austin-fireworks.jpg" alt="">
<img src="taj-mahal_copy.jpg" alt="">
<img src="ibiza.jpg" alt="">
<img src="ankor-wat.jpg" alt="">
<img src="austin-fireworks.jpg" alt="">
CSS:
@keyframes slidy {
0% { left: 0%; }
20% { left: 0%; }
25% { left: -100%; }
45% { left: -100%; }
50% { left: -200%; }
70% { left: -200%; }
75% { left: -300%; }
95% { left: -300%; }
100% { left: -400%; }
}
body { margin: 0; }
div#slider { overflow: hidden; }
div#slider figure img { width: 20%; float: left; }
div#slider figure {
position: relative;
width: 500%;
margin: 0;
left: 0
text-align: left;
font-size: 0;
animation: 30s slidy infinite;
}
9. Memory leaks
A memory leak refers to a situation where an application finishes using memory but does not return it to the underlying OS to be used by another application or process. Every time you create an object or variable in JavaScript, memory is consumed. JavaScript memory leaks occur when you are technically finished with an object or variable but the JS runtime still thinks you need it. This can cause a drag on system performance as resources that should otherwise be freed up for other processes and applications are no longer available.
The best way to avoid JavaScript memory leaks is to properly manage your scope. Here are some common examples of how memory leaks occur in JavaScript:
Accidental global variables
Globally scoped variables are accessible to all scripts and functions in a JavaScript document. For this reason, global variables are not automatically cleaned up by JavaScript’s garbage collector. It’s important to use global variables sparingly and to remember to manually null or reassign them after use. null or reassign them after use.
Hanging outer-function variables in closures
A closure is a function that is nested within a function—in other words, an inner or enclosed function. Closures have access to the variables and scope of the outer function. Similar to accidental global variables, it’s possible for a function declared in the outer scope to still be residing in memory after the outer function has executed because some inner function still has access but isn’t using it.
Detached DOM/Out of DOM references
The document object model (DOM) is a doubly-linked tree in which any reference to any node in the tree will prevent the entire tree from garbage collection. A detached DOM occurs when a node is removed from the tree but is still retained in memory by a reference within JavaScript. If you don’t handle the reference in JavaScript, the garbage collector will not sweep the reference and your code will continue to consume memory.
10. Limit variable calls
Declaring variables and calling back on them for references is the bread and butter of coding. But as we discussed previously every time JavaScript holds a reference to a variable, memory is consumed, and the potential for memory leaks increases. As we already covered above, accidental global variables, hanging closures, and out-of-dOM references can all have the potential to impact performance via memory leaks.
Simply limiting the number of variable calls can lead to writing more concise performant code. If you find yourself declaring too many variables, consider if there is a better way to write your function to achieve the same result with better performance.
11. Reduce DOM and access size
The Document Object Model or DOM is a data representation of the objects that make up the structure of a web page. All web pages are documents (usually HTML) and every object within a document is called a node. JavaScript manipulates the DOM and its nodes directly to change structure, style, and content in response to user input.
Every time your JavaScript code accesses a DOM element or makes a change to the DOM, depending on what you’re doing, you trigger a re-render of part or all of the document. This uses memory and can slow performance if your system has to recalculate lots of nodes within a large DOM.
Trimming large DOM trees is a good place to start when optimizing front-end code. Benefits of keeping your DOM small include:
• Improved network efficiency and load performance
• Better runtime performance (i.e., fewer DOM nodes to access, recompute, or style)
• Reduced risk of memory leaks (i.e., easier to avoid Out of DOM references).
Ways you can minimize your DOM include:
• Keep CSS rules simple
• Minimize DOM references
• Avoid complex animations or remove them from the flow
• Limit the number of DOM elements affected by a change through componentization.
12. Code splitting
Code splitting is the practice of splitting your code across functional components within smaller files that can be called on an as-needed basis. While the total amount of code is more or less the same as if you used a single JavaScript file, it replaces the load time of loading a single large JavaScript file with fractional load times for specific functions and features of your application. You can use a bundler like Webpack to split your code into chunks for app optimization.
13. Use Web Workers
Web Workers allow you to spawn new background threads to run scripts while the main application thread continues to serve the end user. This allows you to perform tasks in the background without interfering with the user interface while someone is using the application.
Technically speaking, a web worker is an object created using a constructor that runs a named JavaScript file containing the code that will run in the worker thread. The web worker is restricted from manipulating the DOM directly.
Benefits of web workers include:
• Frees up resources for the single thread available to JavaScript applications.
• Allows you to hide large, time-consuming tasks from the end user.
• A quick workaround that approximates concurrent multithr
eaded JavaScript
Conclusion
As you can see, there are numerous technologies and techniques to help you with optimization of JavaScript code to speed up download and rendering times.