Blog

  • Home /
  • Blog /
  • Taking Toddler Steps with Node.js – The Towering Inferno Revisited

Taking Toddler Steps with Node.js – The Towering Inferno Revisited

August 15, 2013

Soon after I started using Node.js, I ran into the phenomenon of multiple nested callbacks that create some kind of horizontal tower effect. The solution I came up with in order to improve the readability of my code was using a library called step, as described in this blog post that I wrote at that time.

Over the past years I switched over to a couple of other control flow libraries that solve the same problem as step, but  eventually I settled on using the async library.

Let’s look back at the problem I used in my original blog post:

image

Here’s the slightly refactored equivalent using async:

Here I’ve used the waterfall method of the async library in order to pass results from one function to the next. Other functions that I often use are series and parallel. Notice that in the addNewFavoritePodcastToFile function I used process.nextTick instead of just invoking the callback. This is done in order to prevent inconsistent behavior of the function. I also wrote about this in the past.

There has been a lot of buzz lately around promises, so I decided to drink some of this kool-aid. Basically, we can achieve the same kind of solution as with the async library.

http.createServer(function(request, response) {
    async.waterfall([
        assembleFilePath,
        readFavoritePodcastsFromFile,
        addNewFavoritePodcastToFile
        ], 
        function(error, favoritePodcasts) {
            if(error)
                return response.end(error);

            response.writeHead(200, {
                'Content-Type': 'text/html', 
                'Content-Length': favoritePodcasts.length
            });

            response.end(favoritePodcasts); 
        }
    );
})
.listen(2000);

function assembleFilePath(callback) {
    var filePath = path.join(__dirname, 'podcasts.txt');
    callback(null, filePath);
}

function readFavoritePodcastsFromFile(podcastsFilePath, callback) {
    fileSystem.readFile(podcastsFilePath, 'utf8', function(error, data) {
        if(error)
            return callback(error);

        callback(null, podcastsFilePath, data);
    });                     
}

function addNewFavoritePodcastToFile(podcastsFilePath, favoritePodcastData, callback) {
    var favoritePodcasts = favoritePodcastData;

    if(-1 == favoritePodcasts.indexOf('Astronomy Podcast')) {
        favoritePodcasts = favoritePodcasts + '\n' + 'Astronomy Podcast';       
        fileSystem.writeFile(podcastsFilePath, favoritePodcasts, function(error) {
            if(error)
                return callback(error);

            callback(null, favoritePodcasts);
        });                     
    }
    else {
        process.nextTick(function() {
            callback(null, favoritePodcasts);
        });     
    }
}

I’ve used the Q library for this code sample. For an excellent introduction to promises and the Q library, check out this great article on the StrongLoop blog. I think the approach using promises looks, uhm … promising as well.

Are you, dear reader, using a control flow library, which one and why?

Until next time.

Profile picture of Jan Van Ryswyck

Jan Van Ryswyck

Thank you for visiting my blog. I’m a professional software developer since Y2K. A blogger since Y2K+5. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Comments

About

Thank you for visiting my website. I’m a professional software developer since Y2K. A blogger since Y2K+5. Curator of the Awesome Talks list. Past organizer of the European Virtual ALT.NET meetings. Thinking and learning about all kinds of technologies since forever.

Contact information

(+32) 496 38 00 82

infonull@nullprincipal-itnull.be