Javascript tips

Understanding the Mighty Event Loop

The event loop is what makes the Node so fast and brilliant. It helps the Node utilize the time efficiently which otherwise would have been wasted while waiting for input and output tasks to complete. The event loop is what makes the Node great at optimizing I/O-bound systems. If your Node.js app needs to perform something CPU-intensive for example computation, hashing of passwords or compressing, then besides the usual task of spawning new processes for CPU-tasks, you will also require to explore options for deferring of the task with setImmediate() or setTimeout(). The code in their callbacks will continue on the next event loop cycle. Unfortunately, nextTick() works on the same cycle contrary to the name.

Use tools to detect problems

Lighthouse is a good performance tool for web pages, it helps you to audit performance, accessibility, best practices, and SEO. Google PageSpeed is designed to help developers understand a website’s performance optimizations and areas for potential improvement. The components are built to identify faults in a website’s compliance with Google’s Web Performance Best Practices, as well as automate the adjustment process. In Chrome you can also use, the More Tools option in the main menu to see the memory and the CPU used by each tab. For even more advanced analysis, you can use the developer tools Performance view in either Firefox or Chrome to analyze different metrics, for example: The performance analysis of devtools allows you to simulate CPU consumption, network, and other metrics while the page is being loaded, so you can identify and fix problems. For a deeper look, it is advisable to use the JavaScript Navigation Timing API, which allows you to measure in detail what each part of your code takes from the programming itself. For applications built on Node.js, the NodeSource Platform is also a great, low-impact way to explore application performance at a very granular level. Comprehensive Node.js metrics help you identify the source of memory leaks or other performance issues and resolve these issues faster.

Implement the optimizations that you would apply in any other programming language

  • Always use the algorithms with the least computational complexity to solve the task with the optimal data structures
  • Rewrite the algorithm to get the same result with fewer calculations
  • Avoid recursive calls
  • Put in variables, the calculations and calls to functions that are repeated
  • Factor and simplify mathematical formulas
  • Use search arrays: they are used to obtain a value based on another instead of using a switch/case statement
  • Make conditions always more likely to be true to take better advantage of the speculative execution of the processor
  • Use bit-level operators when you can to replace certain operations, because these operators use fewer processor cycles

Avoid using global variables

Because the scripting engine needs to look through the scope when referencing global variables from within function or another scope, the variable will be destroyed when the local scope is lost. If variables in the global scope can not persist through the lifetime of the script, the performance will be improved.

Prioritize access to local variables

JavaScript first searches to see if a variable exists locally, then searches progressively in higher levels of scope until global variables. Saving variables in a local scope allows JavaScript to access them much faster. Local variables are found based on the most specific scope and can pass through multiple levels of scope, the look-ups can result in generic queries. When defining the function scope, within a local variable without a preceding variable declaration, it is important to precede each variable with let or const in order to define the current scope in order to prevent the look-up and to speed up the code.

If you access a DOM item several times, save it in a local variable

Accessing the DOM is slow. If you are going to read the content of an element several times, it's better to save it in a local variable. But it’s important to keep in mind, if you will later remove the value of the DOM, the variable should be set to "null", so it doesn’t cause any memory leaks.

Use web workers when you need to execute code that needs a lot of execution time

According to the Mozilla Developers Network (MDN) documentation: “Web Workers makes it possible to run a script operation in a background thread separate from the main execution thread of a web application. The advantage of this is that laborious processing can be performed in a separate thread, allowing the main (usually the UI) thread to run without being blocked/slowed down.” Web workers allow your code to perform processor-intensive calculations without blocking the user interface thread. Web Workers allow you spawn new threads and delegate work to these threads for efficient performance. This way, long running tasks which would normally block other tasks are passed off to a worker and the main thread can run without being blocked.

Avoid memory leaks

If a memory leak is ongoing, the loaded page will reserve more and more memory, eventually occupying all the available memory of the device and severely impacting performance. You’ve probably seen (and likely been frustrated by) this type of failure, likely on a page with a carousel or image slider. In Chrome Dev Tools, you can analyze if your website has memory leaks by recording a timeline in the Performance tab. Usually, memory leaks come from pieces of the DOM that are removed from the page but have some variable that makes reference to them and, therefore, the garbage collector can not eliminate them.

Defer the load of JavaScript that is not necessary

Users want to see a page load quickly, but it’s not likely that all functions need to be available for the initial load of the page. If a user must perform a certain action in order for a function to be executed (e.g. by clicking on an element, or changing tabs), it’s possible to defer loading that function until after the initial page load. In this way you can avoid loading and compiling JavaScript code that would delay the initial display of the page. Once the page is fully loaded, we can start loading those functionalities so that they are available immediately when the user starts to interact. In the RAIL model, Google recommends that this deferred load to be done in blocks of 50ms, so that it does not influence the user's interaction with the page.

Avoid using too much memory

You should always try to limit memory use to what is absolutely necessary, because is not possible to know how much memory is required by the device being used to run your app. Any time your code requests that the browser reserve new memory, the browser’s garbage collector is executed, and JavaScript is stopped. If this happens frequently, the page will work slowly.