Home >Web Front-end >JS Tutorial >10 performance optimization tips for nodejs_node.js
Here are 10 performance rules we follow when using Node.js:
1. Avoid using synchronous code
By design, Node.js is single-threaded. To enable a single thread to handle many concurrent requests, you can never have a thread wait for blocking, synchronous, or long-running operations. A distinctive feature of Node.js is that it is designed and implemented from top to bottom to achieve asynchronous implementation. This makes it ideal for event-based programs.
Unfortunately, it is still possible for synchronous/blocking calls to occur. For example, many file system operations have both synchronous and asynchronous versions, such as writeFile and writeFileSync. Even if you use code to control the synchronization method, it is still possible to inadvertently use an external function library that blocks calls. When you do this, the impact on performance is huge.
// Good: write files asynchronously fs.writeFile('message.txt', 'Hello Node', function (err) { console.log("It's saved and the server remains responsive!"); }); // BAD: write files synchronously fs.writeFileSync('message.txt', 'Hello Node'); console.log("It's saved, but you just blocked ALL requests!");
Our initialization log implementation inadvertently included a synchronous call to write the contents to disk. If we don't do performance testing, it will be easy to ignore this problem. When tested against a node.js instance in the developer box, this synchronous call will cause performance to drop from thousands of requests per second to only a few dozen.
2. Close the socket pool
The Node.js http client automatically uses socket pooling: by default, it limits each host to 5 sockets. While socket reuse may keep resource increases under control, it can lead to a series of bottlenecks if you need to handle many concurrent requests for data coming from the same host. In this case, it is a good idea to increase the value of maxSockets or turn off the socket pool:
// Disable socket pooling var http = require('http'); var options = {.....}; options.agent = false; var req = http.request(options)
3. Don’t let static resources use Node.js
For static resources such as css and images, use standard WebServer instead of Node.js. For example, LinkedIn Mobile uses nginx. We also utilize Content Delivery Networks (CDNs), which can copy static assets to servers around the world. This has two benefits: (1) It can reduce the load on our node.js server (2) CDNs can reduce waiting time by allowing static content to be delivered on servers closer to users.
4. Rendering on the client
Let’s quickly compare the differences between server rendering and client rendering. If we use node.js to render on the server side, for every request we will send back an HTML page like the following:
<!-- An example of a simple webpage rendered entirely server side --> <!DOCTYPE html> <html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello John! </div> </body> </html>
Please note that all content on this page, except for the user's name, is static content: the content is the same for each user and page reload. Therefore, it is more efficient to let Node.js return only the dynamic content required by the page in JSON form.
{"name": "John"}
The rest of the page—all static HTML markup—can be placed in a JavaScript template (such as the underscore.js template):
<!-- An example of a JavaScript template that can be rendered client side --> <!DOCTYPE html> <html> <head> <title>LinkedIn Mobile</title> </head> <body> <div class="header"> <img src="http://mobile-cdn.linkedin.com/images/linkedin.png" alt="LinkedIn"/> </div> <div class="body"> Hello <%= name %>! </div> </body> </html>
The performance improvement comes from these places: As mentioned in the third point, static JavaScript templates can be provided on the server side through the webserver (such as nginx), or implemented using a better CDN. In addition, JavaScript templates can be cached in the browser or stored locally. After all initial page loads, the only data that needs to be sent to the client is JSON, which will be most effective. This method can greatly reduce CPU, IO, and Node.js load.
5. Use gzip
Many servers and clients support gzip to compress requests and responses. Whether answering clients or sending requests to remote servers, be sure to use it to its full potential.
6. Parallelization
Try to parallelize all your blocking operations - requests to remote services, DB calls, file system accesses. This will reduce the wait time of the slowest blocking operation, rather than the wait time of all blocking operations. To keep callbacks and error handling clean, we use Step to control the flow.
7.Session liberalization
LinkedIn Mobile uses the Express framework to manage the request/response cycle. Many express examples include the following configuration:
app.use(express.session({ secret: "keyboard cat" }));
By default, session data is stored in memory, which adds huge overhead to the server, especially as the number of users increases. You can use an external session store, such as MongoDB or Redis, but each request will incur the overhead of a remote call to retrieve the session data. Where possible, the best option is to store all stateless data on the server side. By freeing up the session by not including the above express configuration, you will see better performance.
8. Using binary modules
If possible, replace JavaScript modules with binary modules. For example, when we switch from a SHA module written in JavaScript to a compiled version for Node.js, we see a huge jump in performance:
// Use built in or binary modules var crypto = require('crypto'); var hash = crypto.createHmac("sha1",key).update(signatureBase).digest("base64");
9. Replace the client library with standard V8 JavaScript
Many JavaScript libraries are created for use on web browsers because the JavaScript environment differs: for example, some browsers support functions like forEach, map, and reduce, but some browsers do not. So client libraries often use a lot of inefficient code to overcome browser differences. In Node.js, on the other hand, you know exactly which JavaScript methods are valid: the V8 JavaScript engine supports Node.js's implementation of ECMAScript as specified in ECMA-262 5th Edition. Simply replace the client library with standard V8 JavaScript functions and you will see significant performance improvements.
10. Keep your code small and light
Using mobile devices can result in slow access and high latency, which tells us to keep our code small and light. Keep the same philosophy for server code as well. Occasionally look back at your decisions and ask yourself questions like: “Do we really need this module?”, “Why are we using this framework, and is the overhead worth it?”, “Can we use an easier way? achieve it?" Smaller and lighter code is usually more efficient and faster.
Try it
We work hard to make our mobile apps fast. Give it a try on the iPhone app, Android app, and HTML5 mobile version and let us know how you do.