Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Most common mistakes to avoid in node.js-


Node.js has given cutting-edge web applications with two-way, real-time connections where both server and client could communicate with each other. Regardless of how difficult Node.js makes writing safe code, and how easy it makes writing highly concurrent code, the platform has been around for quite a while and has been used to build a number of robust and sophisticated web services. These web services scale well and have proven their stability through their stability through their endurance of time on the internet.

But just like any other platform, Node.js is vulnerable to developer issues. Some of these mistakes lower the performance, while others make Node.js appear straight-out unusable for what you are trying to achieve. Here we’ll discuss the most common errors that Node.js developers make, and how they can be avoided.

Most common mistakes to avoid in Node.js development-

  1. Event loop blocking-

Being a single-threaded environment, no two parts of apps can run in parallel. Since Node.js runs on a single thread, anything that blocks event looks, blocks everything. Concurrency is achieved by handling input-output operations asynchronously. For instance, What allows Node.js to focus on other parts of the app is a request to the database engine, from Node.js to fetch some documents. 

// Trying to fetch a user object from the database. Node.js is free to run other parts of the code from the moment this function is invoked…

db.User.get(userId, function(err, user) {

// .. until the moment the user object has been retrieved here

})

But a part of CPU-bound code in Node.js instance with thousands of clients connected is all it takes to block the event loop, that makes all the clients wait. CPU- bound codes include attempting to sort a large array, running a long loop, and so on. For instance:

function sortUsersByAge(users) {

users.sort(function(a, b) {

return a.age

})

}

Calling this “SortUsersByAge” Function may be fine if run on a small “users” array, but with a large array, it will have a horrible impact on performance. If this must be done and you’re certain that there will be nothing waiting on the event loop(for instance, if this was part of a command line tool that you’re building with Node.js and it wouldn’t matter if the entire thing ran synchronously), then this may not be an issue.

But in a Node.js server instance trying to serve thousands of users simultaneously, such a pattern can prove fatal. 

If users array was retrieved from the database, the best solution will be- to fetch it already sorted directly from the database. If event loop blocked by loop written to compute the financial transaction data, it could be deferred to some external worker/queue setup to avoid hogging the event loop.

There’s no perfect solution for this type of Node.js problem, instead every case needs to be addressed individually. Main idea is to not do CPU intensive work within front-facing Node.js instances- the ones client connect to concurrently. 

2.Deeply Nesting Callbacks-

Generally, nested Callbacks referred to as “callback hell”, is not a Node.js issue in itself. But this can cause problems making code quickly spin out of control:

function handleLogin(…, done) {

db.User.get(…, function(…, user) {

if(!user) {

return done(null, ‘failed to log in’)

}

utils.verifyPassword(…, function(…, okay) {

if(okay) {

return done(null, ‘failed to log in’)

}

session.login(…, function() {

done(null, ‘logged in’)

})

})

})

}

In this way, by nesting callbacks, you can easily end up with error-prone, hard-to-read, and also maintain code.

One solution is to declare these tasks as small functions and then link them. Though the clean solution is to use a utility Node.js package that manages asynchronous Javascript patterns like Aync.js:

function handle login(done) {

async.waterfall([

function(done) {

db.User.get(…, done)

},

function(user, done) {

if(!user) {

return done(null, ‘failed to log in’)

}

utils.verifyPassword(…, function(…, okay) {

done(null, user, okay)

})

},

function(user, okay, done) {

if(okay) {

return done(null, ‘failed to log in’)

}

session.login(…, function() {

done(null, ‘logged in’)

})

}

], function() {

// …

})

}

Just like “async.waterfall”, there are lost of functions that Async.js provides manage with different asynchronous patterns. 

3.Invoking callbacks, multiple times-

Javascript is popular because of relying on callbacks. Callbacks were the only way asynchronous elements of your code communicated with each other in Node.js until promises came into picture. Still package developers  design their APIs around callbacks and hence callbacks are in use. Mistake that developers make while using callbacks is calling them multiple times.

Callback is not end point of current function. Some programmers choose to add a return before calling back to avoid multiple invocations. In lots of asynchronous functions, the return statement has no significance and helps to avoid this problem. Keeping an eye out for this error is all it takes to avoid it. 

4. Callbacks don’t run synchronously, don’t expect them to-

Asynchronous programming with callbacks might not be unique to Javascript and Node.js but are the reason for their popularity. With other programming languages, we are familiar with predictable order of execution where two statements will execute one after another, except if there is a specific instruction to bounce between statements. 

And still, these are generally limited to conditional statements, loop statements, and function invocations. But in Javascript, with callbacks, a specific function may not run well until the task is finished. Execution of current function will run till the end without any stop:

function testTimeout() {

console.log(“Begin”)

setTimeout(function() {

console.log(“Done!”)

}, duration * 1000)

console.log(“Waiting..”)

}

Calling the “testTimeout” function will initially print “Begin”, then print “Waiting..” followed by the message “Done!” after a second.

Anything that should be happen after a callback has been fired needs to be invoked from within it,

5.Aynchronous error handling-

If the V8 engine is the heart of Node.js, callbacks are veins enabling a balanced, non-blocking flow of asynchronous control across modules and apps. “Error-first” callback protocol ensures callbacks could work at scale. Now, Javascript can throw and catch exceptions in try-catch blocks. However in an asynchronous situation, tyr-catch won’t behave as you expect it to. For example, if you want to protect a huge code with one try-catch block, it might not work. The scope containing try-catch block might’ve long gone out of context for it to be still, has the capability to catch the errors thrown from inside the callback. Hence most of the Node.js programmers follow a pattern for all arguments to the callback function, where the first argument of all callbacks is reserved for the error object.

6.Using Console.log for Debugging Purposes-

“console.log” in Node.js allows you to print anything to console. Pass an object to it and it will print it as a Javascript object literal. It accepts an arbitrary number of arguments and prints all space-separated. There are lots of reasons of why programmer feel tempted to use it to debug his code; but recommended to avoid “console.log” in real code. 

You should avoid the writing of “console.log” all over the code to debug it and then commenting when no longer required. Rather,use one of the great library build only for this like debug. 

Such packages provide convenient ways to enable and disable some debug lines when you start the app.For instance, with debug, it is possible to prevent any debug lines from being printed to the terminal by not setting the DEBUG environment variable. Let’s see how to use it:

// app.js

var debug = require(‘debug’)(‘app’)

debug(‘Hello, %s!’, ‘world’)

To enable debug lines, just run this code with environment variable DEBUG set to “app” or “*”: 

DEBUG=app node app.js

7. Zero monitoring or profiling-

Profiling or not monitoring a Node app leaves you in dark. Supervisor program monitor is highly useful to have whether your Node.js code is in production mode or running in your local development environment. Proprietary services like the ones from New Relic, StrongLoop or Concurix, and AppDynamics.  Whatever you select, ensure that you are always aware of the status of the app.

8. Ignoring the benefit of Streaming APIs-

Consider that, you want to build a small proxy-like web server that serves responses to requests by fetching the content from another web server. For instance, you will build a small web server that serves Gravatar images:  

var http = require(‘http’)

var crypto = require(‘crypto’)

http.createServer()

.on(‘request’, function(req, res) {

var email = req.url.substr(req.url.lastIndexOf(‘/’)+1)

if(!email) {

res.writeHead(404)

return res.end()

}

var buf = new Buffer(1024*1024)

http.get(‘http://www.gravatar.com/avatar/’+crypto.createHash(‘md5’).update(email).digest(‘hex’), function(resp) {

var size = 0

resp.on(‘data’, function(chunk) {

chunk.copy(buf, size)

size += chunk.length

})

.on(‘end’, function() {

res.write(buf.slice(0, size))

res.end()

})

})

})

.listen(8080)

In this example of Node.js problem, we are fetching the image from Gravatar, reading it into a Buffer, and then responding to the request. This isn’t bad to do, given that Gravatar images are not too much large. But imagine if the size of contents we are proxying were thousands of megabytes in size. Better approach would be- 

http.createServer()

.on(‘request’, function(req, res) {

var email = req.url.substr(req.url.lastIndexOf(‘/’)+1)

if(!email) {

res.writeHead(404)

return res.end()

}

http.get(‘http://www.gravatar.com/avatar/’+crypto.createHash(‘md5’).update(email).digest(‘hex’), function(resp) {

resp.pipe(res)

})

})

.listen(8080)

Here, we fetch the image and simply pipe the response to client. At no point do we need to read the entire content into a buffer before serving it. 

Final Words-

Lots of developers are using Node.js and there are lots of mistakes that developers make. Above mentioned mistakes are just the common mistakes that developers can avoid for the effective Node.js development. If you’re going to use Node.js for your next project, then this blog will surely help you to avoid the common mistakes. You can consult with the Solace team for an effective node.js development. We are here to help you through consultation and development. You can hire Node.js developers of Solace team for effective Node.js development. Connect with us and get a free quote for software development. We will be happy to help you.


Referral links-

  • https://blog.devgenius.io/9-common-mistakes-node-js-developers-make-b27e3a4aac5d
  • https://codeforgeek.com/top-nodejs-mistakes/
  • https://www.cognitiveclouds.com/insights/common-mistakes-that-node-js-developers-make/

The post Most common mistakes to avoid in node.js- first appeared on Blog.



This post first appeared on Confused About- Native VS Hybrid App Development: Which One To Choose?, please read the originial post: here

Share the post

Most common mistakes to avoid in node.js-

×

Subscribe to Confused About- Native Vs Hybrid App Development: Which One To Choose?

Get updates delivered right to your inbox!

Thank you for your subscription

×