Performance is one of the most important issues facing web and app developers. No one wants to see an app crash under heavy load or a page that takes forever to load. Website users aren't willing to wait too long for websites to load or for their pages to become usable. According to Kissmetrics , 47% of visitors expect a website to load in less than 2 seconds. 40% of visitors will abandon a site if it takes more than 3 seconds to load. The author of the article, whose translation we are publishing today, says that given these figures, it becomes clear that performance is something web developers should always keep in mind. Here are 12 recommendations for improving the performance of JavaScript projects.

There are two main ways to cache data in browsers. The first is using the JavaScript Cache API, which is implemented using service workers. The second is a regular HTTP cache.
Scripts are often used to organize access to specific objects. Storing a reference to a frequently accessed object in a variable, and using this variable in repeated operations that require access to the object, can improve code performance.
To adequately evaluate improvements made to a program, it is recommended to create a set of environments in which measurements can be performed.
In practice, it will be impossible to conduct code performance studies, for example, in all existing versions of JS engines, nor to optimize code for all environments in which it may run. However, it should be noted that testing code in a single environment is also not best practice. This approach can produce distorted results. Therefore, it is important to create a set of environments in which the code is most likely to run and test projects in these environments.
Removing unused code from your project will improve not only the time it takes for browsers to load scripts, but also the time it takes for browsers to parse and compile the code. To get rid of unused code, it's important to pay attention to the project's operating system. For example, if you discover a feature that users aren't using, consider removing it from the project, along with any associated JavaScript code. This will result in the site loading faster and preparing for use in the browser more quickly. This will improve the user experience. When analyzing your project, consider that, for example, a library included in it may have been included by mistake. It may well not actually be used, and it should be removed. The same applies to the use of dependencies that implement features already implemented in modern browsers. Consequently, switching to standard browser features, duplicated by this dependency, will help eliminate unnecessary code.
It's important to ensure that web projects use only the memory they absolutely need. The problem is that developers can't know in advance how much memory their application will have available on a given device. If an application unnecessarily uses large amounts of memory, it places an increased load on the browser's JavaScript engine's memory management mechanisms. This particularly applies to the garbage collector. Frequent garbage collection calls lead to slowdowns, which negatively impacts the project's usability.
Users want web pages to load as quickly as possible. However, a project's entire JavaScript code is unlikely to be required for the initial display of a page. If a user needs to perform an action to activate some code (for example, clicking on an element or switching to a tab in an application), then the loading of this code can be deferred, running it after the initial page load and the most important resources.
This approach prevents the browser from downloading and compiling a large amount of JavaScript code at the very beginning, thereby avoiding the slowdown in page rendering caused by these operations. After the most important code has finished loading, additional code can begin loading. As a result, when the user needs this code, it will already be available. According to the RAIL model , Google recommends lazy-loading sessions of approximately 50 ms. With this approach, code loading operations will not affect the user's interaction with the page.
If your app has a memory leak, it will result in the loaded page requesting more and more memory from the browser. As a result, the page's memory consumption can reach a level that negatively impacts the performance of the entire system. You've likely encountered this problem yourself (and probably didn't like it). It's quite possible that the page with the memory leak contained some kind of image viewer—like a slider or carousel.
You can use Chrome Developer Tools to analyze your site for memory leaks. This is done by examining metrics in the Performance tab. Memory leaks typically result from DOM fragments that have been removed from the page but are still bound to variables. This prevents the garbage collector from cleaning up the memory occupied by these unneeded DOM fragments.
As MDN explains, web workers allow code to run on a background thread separate from the main thread of a web application. The advantage of this approach is that heavy computations can be performed on a separate thread. This allows the main thread (usually responsible for maintaining the user interface) to run without blocking or slowing down.
Web workers allow CPU-intensive computations to be performed without blocking the user interface thread. This technology allows new threads to be created and assigned tasks, which has a beneficial effect on application performance. With this approach, time-consuming tasks do not block other tasks. When such tasks are executed on the main thread, other tasks are blocked.
Obtaining a reference to a DOM element is a slow operation. If you plan to access the element multiple times, it's best to store the reference in a local variable. However, it's important to remember that if the element referenced in the variable is later removed from the DOM, the reference to it must also be removed from the variable. For example, you can do this by assigning the value to the variable null. This will prevent memory leaks.
When attempting to access a variable, JavaScript first searches for it in the local scope. If it isn't found there, the search continues in the scopes within which the local scope is nested. This continues until global variables are checked. Keeping variables in local scopes speeds up access.
Avoid using the keyword when declaring variables unless absolutely necessary . Instead, use the and varkeywords for declaring variables and constants, respectively . They feature block scoping and some other useful features. Be careful when using variables in functions, ensuring that variables accessed within a function are local to it. Be aware of the potential problems of implicitly declaring global variables.letconst
Global variables exist for the entire duration of a script's execution. Local variables are destroyed when their local scope is destroyed. Therefore, global variables should only be used when truly necessary.
For analyzing various aspects of web projects, Lighthouse is recommended. It rates applications based on the following metrics: Performance, Progressive Web App, Accessibility, Best Practices, and SEO. Lighthouse not only rates the application but also provides recommendations for project improvement. Another performance analysis tool, Google PageSpeed , is designed to help developers analyze their websites and identify areas for potential improvement.
Both Lighthouse and PageSpeed are not perfect tools, but they can help identify problems that may not be immediately apparent.
In the Chrome menu, you can find a command that opens the Task Manager. It displays information about the system resources used by open browser tabs. More detailed information about what's happening on a page can be obtained by opening the Performance tab of Chrome's developer tools (similar tools are available in other browsers). This tab allows you to analyze a variety of metrics related to website performance.
The Performance tab in Chrome Developer Tools
When Chrome collects page performance data, you can adjust the CPU and network resources available to your pages, allowing you to identify and fix problems.
Analyzing Page Performance in Chrome
For a more in-depth website analysis, you can use the Navigation Timing API. It allows you to measure various metrics directly in your application code.
If you develop server-side JavaScript projects using Node.js, you can use the NodeSource platform for in-depth analysis of your applications. Measurements performed by this platform have a minimal impact on the project. In the Node.js environment, just like in the browser, many problems can arise, such as memory leaks. Analyzing Node.js-based projects helps identify and fix performance issues.
It's important to maintain a balance between code optimization and readability. Code is interpreted by computers, but it must be maintained by humans. Therefore, code must be understandable not only by computers but also by humans.
Furthermore, it's useful to remember that performance should always be taken into account, but it shouldn't be more important than ensuring error-free code and delivering the app features users need.
Dear readers! How do you optimize your JS projects?

1. Use browser caching mechanisms
There are two main ways to cache data in browsers. The first is using the JavaScript Cache API, which is implemented using service workers. The second is a regular HTTP cache.
Scripts are often used to organize access to specific objects. Storing a reference to a frequently accessed object in a variable, and using this variable in repeated operations that require access to the object, can improve code performance.
2. Optimize your code for the environments in which it will be executed
To adequately evaluate improvements made to a program, it is recommended to create a set of environments in which measurements can be performed.
In practice, it will be impossible to conduct code performance studies, for example, in all existing versions of JS engines, nor to optimize code for all environments in which it may run. However, it should be noted that testing code in a single environment is also not best practice. This approach can produce distorted results. Therefore, it is important to create a set of environments in which the code is most likely to run and test projects in these environments.
3. Get rid of unused JS code
Removing unused code from your project will improve not only the time it takes for browsers to load scripts, but also the time it takes for browsers to parse and compile the code. To get rid of unused code, it's important to pay attention to the project's operating system. For example, if you discover a feature that users aren't using, consider removing it from the project, along with any associated JavaScript code. This will result in the site loading faster and preparing for use in the browser more quickly. This will improve the user experience. When analyzing your project, consider that, for example, a library included in it may have been included by mistake. It may well not actually be used, and it should be removed. The same applies to the use of dependencies that implement features already implemented in modern browsers. Consequently, switching to standard browser features, duplicated by this dependency, will help eliminate unnecessary code.
4. Use memory sparingly
It's important to ensure that web projects use only the memory they absolutely need. The problem is that developers can't know in advance how much memory their application will have available on a given device. If an application unnecessarily uses large amounts of memory, it places an increased load on the browser's JavaScript engine's memory management mechanisms. This particularly applies to the garbage collector. Frequent garbage collection calls lead to slowdowns, which negatively impacts the project's usability.
5. Use lazy loading mechanisms for non-essential scripts
Users want web pages to load as quickly as possible. However, a project's entire JavaScript code is unlikely to be required for the initial display of a page. If a user needs to perform an action to activate some code (for example, clicking on an element or switching to a tab in an application), then the loading of this code can be deferred, running it after the initial page load and the most important resources.
This approach prevents the browser from downloading and compiling a large amount of JavaScript code at the very beginning, thereby avoiding the slowdown in page rendering caused by these operations. After the most important code has finished loading, additional code can begin loading. As a result, when the user needs this code, it will already be available. According to the RAIL model , Google recommends lazy-loading sessions of approximately 50 ms. With this approach, code loading operations will not affect the user's interaction with the page.
6. Avoid memory leaks
If your app has a memory leak, it will result in the loaded page requesting more and more memory from the browser. As a result, the page's memory consumption can reach a level that negatively impacts the performance of the entire system. You've likely encountered this problem yourself (and probably didn't like it). It's quite possible that the page with the memory leak contained some kind of image viewer—like a slider or carousel.
You can use Chrome Developer Tools to analyze your site for memory leaks. This is done by examining metrics in the Performance tab. Memory leaks typically result from DOM fragments that have been removed from the page but are still bound to variables. This prevents the garbage collector from cleaning up the memory occupied by these unneeded DOM fragments.
7. If you need to perform some heavy calculations, use web workers
As MDN explains, web workers allow code to run on a background thread separate from the main thread of a web application. The advantage of this approach is that heavy computations can be performed on a separate thread. This allows the main thread (usually responsible for maintaining the user interface) to run without blocking or slowing down.
Web workers allow CPU-intensive computations to be performed without blocking the user interface thread. This technology allows new threads to be created and assigned tasks, which has a beneficial effect on application performance. With this approach, time-consuming tasks do not block other tasks. When such tasks are executed on the main thread, other tasks are blocked.
8. If you access a DOM element multiple times, store a reference to it in a variable
Obtaining a reference to a DOM element is a slow operation. If you plan to access the element multiple times, it's best to store the reference in a local variable. However, it's important to remember that if the element referenced in the variable is later removed from the DOM, the reference to it must also be removed from the variable. For example, you can do this by assigning the value to the variable null. This will prevent memory leaks.
9. Try to declare variables in the same scope in which they will be used
When attempting to access a variable, JavaScript first searches for it in the local scope. If it isn't found there, the search continues in the scopes within which the local scope is nested. This continues until global variables are checked. Keeping variables in local scopes speeds up access.
Avoid using the keyword when declaring variables unless absolutely necessary . Instead, use the and varkeywords for declaring variables and constants, respectively . They feature block scoping and some other useful features. Be careful when using variables in functions, ensuring that variables accessed within a function are local to it. Be aware of the potential problems of implicitly declaring global variables.letconst
10. Try not to use global variables
Global variables exist for the entire duration of a script's execution. Local variables are destroyed when their local scope is destroyed. Therefore, global variables should only be used when truly necessary.
11. Apply code optimizations to JavaScript that you would apply to programs written in other languages
- Always use algorithms with the lowest possible computational complexity, solve problems using optimal data structures.
- Optimize the algorithms you use to achieve the same results with fewer calculations.
- Avoid recursive calls.
- Formulate repetitive sections of calculations as functions.
- Simplify mathematical calculations.
- Use search arrays instead of switch/case constructs.
- Strive to ensure that the conditions tested in conditional statements are true more often. This promotes more efficient use of the processor's predictive execution capabilities.
- If you have the ability to use bitwise operators to perform certain operations, do so. Such calculations require fewer processor resources.
12. Use tools to research application performance
For analyzing various aspects of web projects, Lighthouse is recommended. It rates applications based on the following metrics: Performance, Progressive Web App, Accessibility, Best Practices, and SEO. Lighthouse not only rates the application but also provides recommendations for project improvement. Another performance analysis tool, Google PageSpeed , is designed to help developers analyze their websites and identify areas for potential improvement.
Both Lighthouse and PageSpeed are not perfect tools, but they can help identify problems that may not be immediately apparent.
In the Chrome menu, you can find a command that opens the Task Manager. It displays information about the system resources used by open browser tabs. More detailed information about what's happening on a page can be obtained by opening the Performance tab of Chrome's developer tools (similar tools are available in other browsers). This tab allows you to analyze a variety of metrics related to website performance.
The Performance tab in Chrome Developer Tools
When Chrome collects page performance data, you can adjust the CPU and network resources available to your pages, allowing you to identify and fix problems.
Analyzing Page Performance in Chrome
For a more in-depth website analysis, you can use the Navigation Timing API. It allows you to measure various metrics directly in your application code.
If you develop server-side JavaScript projects using Node.js, you can use the NodeSource platform for in-depth analysis of your applications. Measurements performed by this platform have a minimal impact on the project. In the Node.js environment, just like in the browser, many problems can arise, such as memory leaks. Analyzing Node.js-based projects helps identify and fix performance issues.
Results
It's important to maintain a balance between code optimization and readability. Code is interpreted by computers, but it must be maintained by humans. Therefore, code must be understandable not only by computers but also by humans.
Furthermore, it's useful to remember that performance should always be taken into account, but it shouldn't be more important than ensuring error-free code and delivering the app features users need.
Dear readers! How do you optimize your JS projects?