简体   繁体   中英

NodeJS async callback. How to return the list, from a async callback?

So basically I am making a database query, to get all posts with a certain id, then add them to a list, so I can return. But the list is returned, before the callback has finished.

How do I prevent it from being returned before callback has finished?

 exports.getBlogEntries = function(opid) {
    var list12 =[];   


    Entry.find({'opid' : opid}, function(err, entries) {

            if(!err) {
           console.log("adding");

            entries.forEach( function(currentEntry){


                list12.push(currentEntry);



            });

            }

            else {
                console.log("EEEERROOR");
            }

            //else {console.log("err");}


          });
    console.log(list12);
    return list12;
    };

You could use sync database calls but that would work around the concept of node.js.

The proper way is to pass a callback to the function that queries the database and then call the provided callback inside the database query callback.

How do I prevent it from being returned before callback has finished?

The callback is asynchronous, and you cannot avoid that. Hence, you must not return a list.

Instead, offer a callback for when it's filled. Or return a Promise for the list. Example:

exports.getBlogEntries = function(opid, callback) {
    Entry.find({'opid': opid}, callback); // yes, that's it.
                                          // Everything else was boilerplate code
};

ALL callback is asynchronous, so we don't have any guarantee if they will run exactly in the order we have leave them.

To fix it and make the process "synchronous" and guarantee an order executation you have two solutions :

  • First : make all process in nested list:

instead of this:

MyModel1.find({}, function(err, docsModel1) {
    callback(err, docsModel1);
});

MyModel2.find({}, function(err, docsModel2) {
    callback(err, docsModel2);
});

use this:

MyModel1.find({}, function(err, docsModel1) {
    MyModel2.find({}, function(err, docsModel2) {
        callback(err, docsModel1, docsModel2);
    });
});

The last snippet above guarantee us that MyModel2 will be executed AFTER MyModel1 is executed.

  • Second : Use some framework as Async . This framework is awesome and have several helper functions to execute code in series, parallels, whatever way we want.

Example:

async.series(
    {
        function1 : function(callback) {
            //your first code here
            //...
            callback(null, 'some result here');
        },
        function2 : function(callback) {
            //your second code here (called only after the first one)
            callback(null, 'another result here');
        }
    },
    function(err, results) {
        //capture the results from function1 and function2
        //if function1 raise some error, function2 will not be called.

        results.function1; // 'some result here'
        results.function2; // 'another result here'

        //do something else...
    }
);

There is an alternate way to handle this scenario. You can use the async module and when the forEach has finished then make the return call. Please find the code snippet below for the same:

var async = requires('async');
exports.getBlogEntries = function(opid) {
var list12 =[];
Entry.find({'opid' : opid}, function(err, entries) {
    if(!err) {
       console.log("adding");
       async.forEachSeries(entries,function(entry,returnFunction){
           list12.push(entry);
       },function(){
           console.log(list12);
           return list12;
       });
    }
    else{
            console.log("EEEERROOR");
    }
  });
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM