For other translations of this series, see [JS Working Mechanism – Xiaobai’s 1991 column – Nuggets (juejin. Cn)] (juejin.cn/column/6988…

This article focuses on Node analysis and is syntactically based. Juejin: How to optimize front end Performance in 2021

The overview

JS is a popular language used in clients, servers, mobile and desktop applications. Therefore, it is necessary to build high performance JS applications. In this chapter, we discuss some of the common problems that cause performance degradation, as well as some suggestions for optimizing performance – which may help you solve some of the big problems.

Common mistakes

We list some common errors that significantly affect our JS performance.

1. Too many third-party libraries or scripts As the application gets bigger, there may be too many Node dependencies, plug-ins, and even scripts that can seriously affect the performance of our application. Therefore, remove unnecessary dependencies.

2. No CDN

One effective way to improve the performance of applications with a lot of Web content is to use CDN. It will deliver static content at high speed from your nearest server.

3. Too many HTTP requests

Your site, through HTTP requests, communicates with the server to display information. This means that the page loads with a lot of requests. If your site loads a lot of scripts and resources, you will have performance problems.

Minimizing JS files will remove comments, shorten variable names, remove whitespace, and also remove useless code. None of this will affect the functionality of the application, but it will shorten the running time because the file size is reduced. Minimize code. There are many tools available.

Optimization hints

We’ll discuss some optimizations to make our JS code perform better

  1. Use promise.all instead of await

This means that instead of waiting for execution, we bind our invocation and unresolved promise into an array. For example, if we want to call two requests to the database, we would normally add await to each call.

const getUsers = async () => {
  const customers = await findAllCustomers();
  const admins = await findAllAdmins();
  
  return { customers, admins }
}
Copy the code

The best way is to call in parallel and resolve the result in nearly half the time:

const getUsers = async () => {
  const customers = findAllCustomers();
  const admins = findAllAdmins();
  return Promise.all([customers, admins]);
}
Copy the code

We let the calls work in parallel to save time waiting for execution.

2. Effective cycles

Using a good loop declaration can also improve the performance of JS applications. Depending on your application or your process, you may want to loop your data declaratively. Loop declarations include for-loop or while loop declarations, as well as declarative *map, reduce, filter, and so on.

Let’s see how we can traverse data using Map, Filter, and Reduce:

// Imagine we had a thousand software engineers data to loop from

const result = allSoftwareEngineers
.map(engineer => engineer.salary)
.filter(salary => salary > 100000)
.reduce((prev, next) => prev + next, 0);
Copy the code

I’m not saying that Map, Reduce, and other methods are bad, just that they tend to be performance bottlenecks when there’s a lot of data. To compare declarative and imperative loops, performance-analysis lets change that.

let results = 0;

for (engineer of allSoftwareEngineers) {
  // Check if salary is above 100000
  if (engineer.salary > 100000) results += engineer.salary;
}
Copy the code

This improves performance by at least three times.

3. Run the app in Cluster

In Node, we can use the Cluster module to run subroutines. Each of the sub-clusters, or processes, we created runs in its own V8, event loop, and memory. The goal is to distribute loads and tasks to each process.

Create a cluster in node:

const express = require('express');
const app = express();
const port = 5000;
const cluster = require('cluster');
const numberOfCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Number of CPUs is ${numberOfCPUs}`);
  console.log(`Master ${process.pid} running`);

  // Fork workers - create a child process.
  for (let i = 0; i < numberOfCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
    console.log("Let's fork another worker!");
    cluster.fork();
  });

} else {
  console.log(`Worker ${process.pid} started`);

  app.get('/', (req, res) => {
    res.send('Hello Worker');
  })

  app.listen(port, () => {
    console.log(`Listening on port ${port}`);
  })
}
Copy the code

We created a cluster of nodes to handle the loading task.

4. Cache response when there are many users

On special occasions, we might want to cache the server’s response so that the user doesn’t have to wait for the same data. During these periods, our application data hardly changes, so instead of querying it in the database, we fetch it directly from the cache 5. Use process management

During development, we use Node app.js to start the project, and if the project crashes, we run it again. But in a publishing environment, you may not be able to restart it. At this point, you need a process manager such as PM2 **** or Forever.

In addition, they provide additional details and observations on performance.

6. Use node.js stream instead of fs.readfile

Using fs.readfile has become a popular way to read files. It reads the entire file and puts it in memory. If you are processing large files, memory and CPU usage will skyrocket. It is better to use the Node stream, which reads files directly from disk and sends them via a response. Use the stream:

const fs = require("fs");
const data = '';

const readerStream = fs.createReadStream('file.txt'); // Create a readable stream

readerStream.setEncoding('UTF8'); // Set the encoding to be utf8. 

// Handle stream events = data, end, and error
readerStream.on('data', function(chunk) {
   data += chunk;
});

readerStream.on('end',function() {
   console.log(data);
});

readerStream.on('error', function(err) {
   console.log(err.stack);
});

console.log("File Read");
Copy the code

7. Use asynchronous functions

Node is single-threaded. If you are doing something that blocks a thread – such as reading from a database/file system or performing a CPU-intensive task – you should use asynchronous functions that do not block the thread.

8. Using HTTP / 2

The latest HTTP protocol version is HTT/2. One of its many benefits is blending, which allows you to use the same TCP connection while accepting parallel requests and responses. In terms of performance, it is much better than HTTP/1 in that it can pass multiple resources to the client at once.