Skip to content Skip to sidebar Skip to footer

Handling Multiple Call Asynchronous Callbacks

I am learning node.js with learnyounode. I am having a problem with JUGGLING ASYNC. The problem is described as follows: You are given three urls as command line arguments. You ar

Solution 1:

This is how I would go about solving the problem.

#!/usr/bin/env nodevar http = require('http');
var argv = process.argv.splice(2),
    truecount = argv.length,
    pages = [];

functionprintUrls() {
  if (--truecount > 0)
    return;
  for (i = 0; i < pages.length; i++) {
    console.log(pages[i].data + '\n\n');
  }
}

functionHTMLPage(url) {
  var _page = this;
  _page.data = '### [URL](' + url + ')\n';
  http.get(url, function(res) {
    res.setEncoding('utf8');
    res.on('data', function(data) {
      _page.data += data;
    });
    res.on('end', printUrls);
  });
}


for (var i = 0; i < argv.length; i++)
  pages.push(newHTMLPage(argv[i]));

It adds the requests to an array on the start of each request, that way once done I can iterate nicely through the responses knowing that they are in the correct order.

When dealing with asynchronous processing, I find it much easier to think about each process as something with a concrete beginning and end. If you require the order of the requests to be preserved then the entry must be made on creation of each process, and then you refer back to that record on completion. Only then can you guarantee that you have things in the right order.

If you were desperate to use your above method, then you could define a variable inside your get callback closure and use that to store the urls, that way you wouldn't end up with the last url overwriting your variables. If you do go this way though, you'll dramatically increase your overhead when you have to use your urls from process.argv to access each response in that order. I wouldn't advise it.

Solution 2:

I went about this challenge a little differently. I'm creating an array of functions that call http.get, and immediately invoking them with their specifc context. The streams write to an object where the key is the port of the server which that stream is relevant to. When the end event is triggered, it adds to that server to the completed array - when that array is full it iterates through and echos in the original order the servers were given.

There's no right way but there are probably a dozen or more ways. Wanted to share mine.

var http = require('http'),
    request = [],
    dataStrings = {},
    orderOfServerInputs = [];
var completeResponses = [];
for(server in process.argv){
    if(server >= 2){
        orderOfServerInputs[orderOfServerInputs.length] = process.argv[server].substr(-4);
        request[request.length] = function(thisServer){
            http.get(process.argv[server], function(response){
                response.on("data", function(data){
                    dataStrings[thisServer.substr(-4)] = dataStrings[thisServer.substr(-4)] ? dataStrings[thisServer.substr(-4)] : ''; //if not set set to ''
                    dataStrings[thisServer.substr(-4)] += data.toString();
                });
                response.on("end", function(data){
                    completeResponses[completeResponses.length] = true;
                    if(completeResponses.length > 2){
                        for(item in orderOfServerInputs){
                            serverNo = orderOfServerInputs[item].substr(-4)
                            console.log(dataStrings[serverNo]);
                        }
                    }
                });
            }); 
        }(process.argv[server]);
    }
}

Solution 3:

Immediately-Invoked Function Expression (IIFE) could be a solution to your problem. It allows us to bind to function a specific value, in your case, the url which gets the response. In the code below, I bind variable i to index and so, whichever url gets the response, that index of print list will be updated. For more information, refer to this website

var http = require('http')
var truecount = 0;
var printlist = [];
for(var i = 2; i < process.argv.length; i++) {
    (function(index){
        http.get(process.argv[index], function(response) {

            response.setEncoding('utf8');
            response.on('data', function(data) {
                if (printlist[index] == undefined)
                    printlist[index] = data;
                else
                    printlist[index]+= data;
            })
            response.on('end', function() {
                truecount += 1if(truecount == 3) {
                    printlist.forEach(function(item) {
                        console.log(item)
                    })
                }
            })
        })
    })(i)
}

Post a Comment for "Handling Multiple Call Asynchronous Callbacks"