articles

Home / DeveloperSection / Articles / Asynchronous Programming In Node.js

Asynchronous Programming In Node.js

Anchal Kesharwani7060 18-Aug-2014

In this article, I’m explaining the concept of asynchronous programming in node.js.

There are two types of programming synchronous way and asynchronous programming way. In the synchronous programming wait for each operation to complete whether asynchronous programming never waits for each operation complete. Let’s we talk about asynchronous programming. Here we explain the asynchronous programming by a real life example:

Let's suppose you go to a bakery shop (and assuming the cake will be prepared after the order) - you have two choices, either you choose to wait till the cake is ready or you give the order and head-back to home and pickup later when it is ready. The first one (wait) is a synchronous method and later is asynchronous method. Needless to say this example provides a good reference why should you use asynchronous methods over synchronous.

I’ve been doing a lot of backend development in Node.js recently. Node.js runs on a single threaded event loop and leverages asynchronous calls for doing various things, like I/O operations. While other languages will send a database query and wait there for the result to come back, Node.js will not. When you send a database query, Node.js will continue executing the code that comes after it, then jump back when the result is available.

This is a powerful concept that enables gains in efficiency, but occasionally requires a bit more work on your end to deal with certain situations. One of those situations, which I’ve run into quite frequently, is the need to wait for a number of asynchronous operations to finish before executing additional code.

Create a program at your location. Here, I saved the location at c:\node;Take a look at this piece of code with three levels deep async callbacks.

var fs = require('fs');

var http = require('http');

var path = './headers.txt';

 

// i. check if headers.txt exists

fs.stat(path, function(err, stats) {

    if (stats == undefined) {

        // ii. fetch the HTTP headers

        var options = {

            host: 'www.google.com’,

            port: 80

        };       

        http.get(options, function(res) {

            var headers = JSON.stringify(res.headers);

            // iii. write the headers to headers.txt

            fs.writeFile(path, headers, function(err) {

                console.log('Great Success!');

            });

        });   

    }

    else { console.log('headers already collected'); }

});

 

With every level it gets worse and worse. Imagine it was 10 levels deep! You must

have figured the async callback problem by now. Let's see how we can fix it.

This problem becomes a no-problem, with the use of an aptly named Node.js

module called async. Let's find out how to use it.

First of all we need to install async package from the NPM:

 npm install async

 

Now here is the modified code with async:

var fs = require('fs');

var async = require('async');

var http = require('http');

var path = './headers.txt';

 

async.waterfall(

    [

        // i. check if headers.txt exists

        function(callback) {

            fs.stat(path, function(err, stats) {

                if (stats == undefined) { callback(null); }

                else { console.log('headers already collected'); }

            });

        },

       

        // ii. fetch the HTTP headers

        function(callback) {

            var options = {

                host: ‘www.google.com’,

                port: 80

            };       

            http.get(options, function(res) {

                var headers = JSON.stringify(res.headers);

                callback(null, headers);

            });

        },

       

        // iii. write the headers to headers.txt

        function(headers, callback) {

            fs.writeFile(path, headers, function(err) {

                console.log('Great Success!');

                callback(null, ':D');

            });

        }

    ],

   

    // the bonus final callback function

    function(err, status) {

        console.log(status);

    }

);

 

Here we give the simple example for async.waterfall that run asynchronously.

While the async module offers many other useful methods, only two of them are enough for most async callbacks in Node.js - series() and waterfall().

Both these methods accept an array of functions to be executed one after another, and an optional callback function which will be executed after all the functions have executed without any errors.

The difference between series() and waterfall() is that the functions in series() are executed one after another and their results stored in a response array in their corresponding indexes, and the response array is passed to the optional final callback function. In waterfall(), the result of each function is passed on to the next function, and the result of the last function is passed to the optional final callback function.

In the above example, we used waterfall() because we needed to pass the result of step ii to the function in step iii.

Another simple example of using waterfall():

var async = require('async');

 

async.waterfall(

    [

        function(callback) {

            callback(null, 'Asychronous', 'Programming');

        },

        function(arg1, arg2, callback) {

            var caption = arg1 +' and '+ arg2;

            callback(null, caption);

        },

        function(caption, callback) {

            caption += ' Rock!';

            callback(null, caption);

        }

    ],

    function (err, caption) {

        console.log(caption);

        // Node.js and JavaScript Rock!

    }

);    function (err, caption) {

        console.log(caption);

        // Node.js and JavaScript Rock!

    }

);

 

Here, first parameter is null in callback (null,caption) is for any error you want to

throw error for null if error parameter is not null.

When the error value is null, the following parameters after null are passed on to the next callback function. Don't expect to find the error parameter in the next function even though it is the first parameter in callback(). It never makes it to the next function. The last parameter of callback() is understood as the next callback function.

Here is an example of using series():

 

var async=require('async')

async.series(

    [

        function(callback) {

            callback(null, 'Asychronous');

        },

        function(callback) {

            callback(null, 'Programming');

        },

    ],

    function(err, response) {

        // response is ['Node.js', 'JavaScript']

    }

);

The second parameter of series() is the optional callback function to which has access to the array of results from all the function series. You may or may not use the callback function, depending on your requirements.

An interesting thing about series() is that you can pass an object instead of an array, with the functions attached to the object keys. The results of functions replace their corresponding functions in the object. Here is an example:

var async=require('async')

async.series({

        one: function(callback) {

                callback(null, 'Asynchronous');

            },

        two: function(callback) {

                callback(null, 'Programming');

            },

    },

    function(err, response) {

                //response == {one: 'Asynchronous', two: 'Programming'}

    }

);

 

I hope that this article is helpful for you. Thanks!


Updated 30-Nov-2017

Leave Comment

Comments

Liked By