Capture value of an asynchronous function in Nodejs

Asked

Viewed 1,004 times

3

Hello, I have a problem I haven’t found a solution.

I have an array of values, in which I scan and for each value run function that makes a request to dynamodb and returns a JSON. This request is asynchronous. With the value of each query, I want to fill an array, which will be returned via callback for my View.

The problem is, when I give one push in Array, it returns me empty when leaving the scope of my asynchronous function.

exports.appCategory = function(ids, callback1){

    var result = { apps: []};

    async.forEachSeries(ids, function(item, cb){
            async.series([
                    function(callback){
                            //funcao assincrona
                            verify(item.id, function(res){
                                    result.apps.push(res);
                            });
                            callback();
                    },
            ]);
            cb();
    });

    console.log(result);
}

My database query function:

function verify(id, callback){

    scrapeDB.getItem(id, function(response){
            var category;
            url = "https://play.google.com/store/apps/details?id="+id+"&hl=pt";

            if(response === null){
                    request(url, function(error, response, html){

                            if(error){
                                    console.log(error);
                                    return false;
                            }else{

                                    var $ = cheerio.load(html);

                                    if(response.statusCode == "404"){
                                            category = "Outros";
                                    }else{
                                            $('.category').filter(function(){
                                                    var data = $(this);
                                                    dataCategory = data.children().first().text();
                                                    category  = dataCategory;
                                            });
                                   }//else

                                   //save data
                                   scrapeDB.putItem(id, category, function(resp){
                                            callback(resp);
                                            //return resp;
                                   });

                            }//else       
                    });//request
            }else{
                    callback(response);
                    //return response;
            }

    });//scrapedb

}//function verify()

My current result is:

{ apps: [] }

The expected result is something similar to (a JSON array):

{ apps: [{id: "value1", category: "category1"}, {id: "value1", category: "category1"}] }
  • Where do you use that async.forEachSeries? in the repository of async.js I can’t find that method...

  • Hi @Sergio, I found this link: http://stackoverflow.com/questions/15942832/nodejs-async-foreachseries-execution-order

1 answer

2


There are several problems with your code but the basic problem is that you are assuming that the line after the asynchronous function call only runs after the server has responded. In fact the opposite is true.

For example, if you rotate

 requestDataFromServer(function(){
     console.log("servidor respondeu");
     array.push(...)
 });
 console.log("agora tudo acabou")

The result you are likely to get will be the opposite of what you expect:

agora tudo acabou
servidor respondeu

To solve this, what you should do is always pass a callback to the asynchronous functions and place all the rest of your execution stream that depends on the result of the asynchronous call within that callback.

exports.appCategory = function(ids, callback1){

    var result = { apps: []};

    async.forEachSeries(ids, function(item, cb){
        async.series([
            function(callback){
                //funcao assincrona
                verify(item.id, function(res){
                    result.apps.push(res);
                    callback();
                });
            },
        ], function(){
            cb()
        });
    }, function(){
        console.log(result);
        callback1();
    });
}

Also, there are some modifications that I think make the code more beautiful in this case:

  • using assinc.series with a size 1 list is redundant
  • function(){ cb() } can be written as cb
  • I think the real name of the function is eachSeries

that is to say:

exports.appCategory = function(ids, callback1){
    var result = { apps: []};
    async.eachSeries(ids, function(item, cb){
        verify(item.id, function(res){
            result.apps.push(res);
            cb()
        });
    }, function(){
        console.log(result);
        callback1();
    });
}

ps: recommend you take a look at the function each (without the "series") to make the code faster and not have to keep giving "push".

  • Hello @hugomg, I understood your reply. As soon as I can, I will make the changes and put here the result. Thank you.

  • @user3319937 if Hugo’s answer solved his problem can mark the answer as accepted.

  • Hello @hugomg, it worked perfectly. Thank you very much for the reply.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.