🔧 Improving JavaScript Performance: Techniques and Best Practices
Nachrichtenbereich: 🔧 Programmierung
🔗 Quelle: dev.to
JavaScript is one of the most popular languages used for web application development, due to its ability to make user interfaces dynamic and interactive. However, as modern web applications become more complex, performance can become a significant issue. A slow or unresponsive application can degrade the user experience, leading to an increase in abandonment rates. In this article, we will explore some of the most effective techniques for improving the performance of JavaScript code.
🔗 Do you like Techelopment? Check out the site for all the details!
1. Code Minification
What does it mean?
Minification is the process of removing whitespace, comments, and unnecessary characters from JavaScript source code, without affecting functionality. Minification tools, such as UglifyJS or Terser, reduce the size of JavaScript files, allowing browsers to download and load them faster.
How does it work?
During minification, variables with long names are shortened, unnecessary comments are removed, and whitespace is trimmed. This reduces the time it takes to download the file.
Example:
// Before minify
function sum(number1, number2) {
return number1 + number2;
}
After minification:
function x(a,b){return a+b}
JavaScript code minification should not be done manually, it is usually handled automatically by tools that do it for you, reducing file size by removing whitespace, comments and other unnecessary elements. Below you will find some very popular tools for JavaScript code minification and how to configure them.
Most common tools for Automatic Minification:
1. Terser
2. UglifyJS
3. Google Closure Compiler
4. Webpack (with the integrated minification plugin)
2. Lazy Loading of Components
What does it mean?
Lazy loading is a technique that consists of loading resources only when they are actually needed. In a complex JavaScript application, loading all the modules or resources at the same time can slow down the page loading. Lazy loading solves this problem by loading only the essential resources initially and postponing the loading of the rest.
Example:
In this case, we dynamically load a JavaScript module only when it is needed, taking advantage of the dynamic import (import()
) functionality, which allows loading JavaScript modules asynchronously.
Imagine we have a file structure like this:
index.html
main.js
myModule.js
- index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lazy Loading Example</title>
</head>
<body>
<h1>Lazy Loading in JavaScript</h1>
<button id="loadModule">Load Module</button>
<div id="output"></div>
<script src="main.js"></script>
</body>
</html>
- myModule.js (the module that will be dynamically loaded):
export function helloWorld() {
return 'Hello from dynamically loaded module!';
}
- main.js (the main JavaScript file that handles lazy loading):
document.getElementById('loadModule').addEventListener('click', async () => {
// Dynamically import the form only when the button is clicked
const module = await import('./myModule.js');
// Execute a function from the newly loaded module
const output = module.helloWorld();
// Show output in DOM
document.getElementById('output').textContent = output;
});
The dynamic import
returns a Promise
, so we use await
to wait for the module to fully load before calling the helloWorld()
function from the imported module.
Debouncing and Throttling
Debouncing
Debouncing is a technique that allows you to limit the frequency with which a function is executed. It is particularly useful for handling events that can be triggered repeatedly in a short time, such as resizing the window or entering characters in a text field.
Example:
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId); // Clear previous timeout
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
// Example of use:
const logTextDebounced = debounce(() => {
console.log('Function performed with debouncing');
}, 2000);
window.addEventListener('resize', logTextDebounced);
Throttling
"Throttling" is similar to debouncing, but instead of delaying the function until the event stops being called, it limits the rate at which the function is executed.
Example:
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
// Example of use:
const logScrollingThrottled = throttle(() => {
console.log('Scrolling!');
}, 200);
window.addEventListener('scroll', logScrollingThrottled);
Using requestAnimationFrame
for Animations
When working with JavaScript animations, using setTimeout
or setInterval
to synchronize animations can cause stuttering and slowdown, because these methods are not synchronized with the display refresh rate. requestAnimationFrame
is a browser API that optimizes animations by synchronizing them with the display refresh rate.
Example:
function animation() {
/* ... animation logic ... */
requestAnimationFrame(animation);
}
requestAnimationFrame(animation);
Benefits:
- Smoother animations
- Less resource consumption because the animation is only executed when needed
Avoid Excessive Loops: Use Optimized Methods
Loops like for
, while
, and forEach
can impact performance, especially when iterating over large amounts of data. JavaScript methods like map()
, filter()
, and reduce()
can be more efficient and readable. Additionally, in many cases, these methods allow code to be more concise and maintainable.
Example:
// Using map to create a new array
const numbers = [1, 2, 3, 4];
const dobule = numbers.map(number => number * 2);
Caching DOM Variables
Whenever you interact with the DOM via JavaScript, such as using document.getElementById
or querySelector
, the browser must navigate through the DOM tree to find the requested element. If this is repeated in a loop, it can significantly slow down performance. To optimize, it is good practice to store references to DOM elements in a variable.
Example:
// Inefficient
for (let i = 0; i < 1000; i++) {
document.getElementById('my-element').innerHTML = i;
}
// Efficient
const element = document.getElementById('my-element');
for (let i = 0; i < 1000; i++) {
element.innerHTML = i;
}
Avoid overuse of eval() and with
Functions like eval()
or with
blocks can reduce performance because they prevent the JavaScript engine from optimizing the code. eval()
runs code inside a string and can introduce security vulnerabilities, as well as slow execution, since the browser has to interpret and compile the code each time.
Example:
Avoid:
eval("console.log('Avoid eval');");
Asynchronous JavaScript loading
To prevent loading JavaScript files from blocking page rendering, you can load scripts asynchronously or deferred by using the async
or defer
attributes in the <script>
tag.
Difference between async and defer:
-
async
: The script is executed asynchronously, so it is loaded in parallel with the parsing of the page and executed as soon as it is ready. -
defer
: The script is loaded in parallel, but is executed only after the page has been fully parsed. The order of execution is also respected.
Example:
<!-- Script loaded asynchronously -->
<script src="script.js" async></script>
<!-- Deferred script -->
<script src="script.js" defer></script>
Minimize Style Recalculation and Reflow
Operations that change the DOM structure or style can cause style recalculation and reflow (reorganizing the arrangement of elements). To improve performance, try to minimize the number of changes that alter the layout of the page.
Example:
Modify the DOM as little as possible:
// Avoid changing the style at each iteration
for (let i = 0; i < max; i++) {
let size += i * window.innerWidth;
element.style.width = `${size}px`;
}
// Better to update all changes together
let size = 0;
for (let i = 0; i < 1000; i++) {
size += i * window.innerWidth;
}
element.style.width = `${size}px`;
Keep an eye on performance…always!
Optimizing the performance of a JavaScript application is essential to ensure a smooth and satisfying user experience. Techniques such as minification, lazy loading, DOM caching, and the appropriate use of methods such as requestAnimationFram
e can significantly improve the speed of code execution. By implementing these best practices, you will not only make your applications faster, but also contribute to a better user experience and greater resource efficiency.
Follow me #techelopment
Official site: www.techelopment.it
Medium: @techelopment
Dev.to: Techelopment
facebook: Techelopment
instagram: @techelopment
X: techelopment
telegram: @techelopment_channel
youtube: @techelopment
whatsapp: Techelopment