0

I am working with javascript for quite some time now and recently started using Nodejs in my project. I have a requirement to make some http calls from my nodejs app and then when all of them are done, need to consolidate and send the response.

In this regards, I was searching and came across async module for Nodejs. (https://github.com/caolan/async)

I also found a blog which nicely explains how to use this feature. (http://justinklemm.com/node-js-async-tutorial/)

The below code snippet is what I am planning to use for my task.

// Include the async package
// Make sure you add "async" to your package.json
async = require("async");

// 1st para in async.each() is the array of items
async.each(items,
  // 2nd param is the function that each item is passed to
  function(item, callback){
  // Call an asynchronous function, often a save() to DB
    item.someAsyncCall(function (){
    // Async call is done, alert via callback
    callback();
  });
},
// 3rd param is the function to call when everything's done
  function(err){
    // All tasks are done now
    doSomethingOnceAllAreDone();
  }
);

In the above I need to make http call instead of item.someAsyncCall section. Specifically the code that I have is

 var formaatedResponse=[];

 request("http://" + API_HOST + "/app/v1/customers/" + element, 
    function (error, response, body) {
      console.log('Ajax call response');
      formaatedResponse.push(JSON.parse(response.body));
  });

How to accommodate my changes since when I tried adding the above code it does not work as intended.

My code:

 function consolidateResponse(){
        console.log("Everything is done.");
        console.log(formaatedResponse);
    }

// 1st para in async.each() is the array of items
    async.each(result,
        // 2nd param is the function that each item is passed to
        function(element, callback){
            // Call an asynchronous function, often a save() to DB

                request("http://" + API_HOST + "/app/v1/customers/" + element, function (error, response, body) {
                    console.log('Ajax call response');
                    formaatedResponse.push(JSON.parse(response.body));
                });
                callback();

        },
        // 3rd param is the function to call when everything's done
        function(err){
            // All tasks are done now
            consolidateResponse();
        }
    );

Regards, Pradeep

6
  • What does it do? Do you get an error? Commented Feb 4, 2015 at 8:53
  • can you copy paste error in console log.It seems to be cross domain call issue or some authorization issue. Commented Feb 4, 2015 at 8:53
  • Please post the code that you are trying, the one that gives the errors Commented Feb 4, 2015 at 8:54
  • There are no errors. The consolidateResponse method is not getting called after all http calls are done but instead called synchronously. Also update the question with my code. Commented Feb 4, 2015 at 9:02
  • Yeah. All the http requests are fired in parallel, and thats what async does. It will not wait for it to end. consolidateResponse() will be called after all the requests are fired Commented Feb 4, 2015 at 9:08

2 Answers 2

1

You should call callback() inside request()'s callback:

request("http://" + API_HOST + "/app/v1/customers/" + element,
        function (error, response, body) {
  console.log('Ajax call response');
  formaatedResponse.push(JSON.parse(response.body));
  callback();
});

This way you're signalling you're done with the particular item when http request actually finishes instead of right after it starts.

Sign up to request clarification or add additional context in comments.

2 Comments

Even this solution is not working: Please see the logs below: Printing the element.... 148624 Printing the element.... 65987 Finally Done.... Everything is done. [] GET /compare-vms/?keywords=+2k8std511+AAAtest 200 16ms - 2b Ajax call response Ajax call response
Make sure you don't still have callback(); right after your request();. It should be moved inside the request() callback, not copied. Other than that, there should be no problems with the code you presented with the changes I suggested.
0

I expect that moving the callback into your call should resolve the issue:

// 1st para in async.each() is the array of items
async.each(result,
    // 2nd param is the function that each item is passed to
    function (element, callback) {
        // Call an asynchronous function, often a save() to DB
        element.someAsyncCall(function () {
            request("http://" + GLASS_API_HOST + "/glass/v1/vmware/vm/" + element, function (error, response, body) {
                console.log('Ajax call response');
                formaatedResponse.push(JSON.parse(response.body));

/*Changed:*/    callback();

            });
        });
    },
    // 3rd param is the function to call when everything's done
    function (err) {
        // All tasks are done now
        consolidateResponse();
    }
);

Explanation: In the previous code, the callback was called immediately after a request was issued, without waiting for the response. By moving the callback to the internal function of the request, you make sure it will not be called before the response is returned.

Also note async.each() works in parallel for all items, so if your result set is extemely large you may want to consider using async.eachLimit which will limit parallel requests to a defined value, or async.eachSeries which will make sure execution of requests is in series.

Another suggestion: You can utilize the callback to handle errors, this way:

request("http://" + GLASS_API_HOST + "/glass/v1/vmware/vm/" + element, function (error, response, body) {
    if(error){
        callback(error);
        return
    }
    console.log('Ajax call response');
    formaatedResponse.push(JSON.parse(response.body));
    callback();
});

And then async.each callback:

// 3rd param is the function to call when everything's done
function (err) {
    if (err) {
        // Handle error here: log it, report it, and return response with err code. example:
        console.error(err);
        // Halt execution;
        return;
    }
    // All tasks are done now, and no error occurred:
    consolidateResponse();
}

So your final code might look like:

// 1st para in async.each() is the array of items
async.each(result,
// 2nd param is the function that each item is passed to
    function (element, callback) {
        // Call an asynchronous function, often a save() to DB
        element.someAsyncCall(function () {
            request("http://" + GLASS_API_HOST + "/glass/v1/vmware/vm/" + element, function (error, response, body) {
                if (error) {
                    callback(error);
                    return
                }
                console.log('Ajax call response');
                formaatedResponse.push(JSON.parse(response.body));
                callback();
            });
        });
    },
// 3rd param is the function to call when everything's done
    function (err) {
        if (err) {
            // Handle error here: log it, report it, and return response with err code. example:
            console.log(err);
            // Halt execution;
            return;
        }
        // All tasks are done now, and no error occurred:
        consolidateResponse();
    }
);

2 Comments

Even moving the callback code inside the function call is not resolving. Below is the log statement. Printing the element.... 14862 Printing the element.... 65987 Finally Done.... Everything is done. [] GET /compare-vms/?keywords=+2k8std511+AAAtest 200 16ms - 2b Ajax call response Ajax call response
This seems to be an issue with the request. Try the siven method of error handling, and use breakpoints to find out what's the problem with the responses. Is the callback called on time? Are the responses correct? What does formaatedResponse object contain when operation is complete?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.