简体   繁体   English

Node.js-函数调用返回未定义并在以后评估

[英]Node.js - Function call returning undefined and evaluated later

I am using the async module to execute a set of function in parallel. 我正在使用异步模块来并行执行一组功能。 However i am using a return value of another function in the callback of on of these function. 但是我在这些函数的on回调中使用了另一个函数的返回值。 But the problem is, function returns as undefined as the callback does not wait for it to be evaluated. 但是问题是,函数返回的值未定义,因为回调函数不会等待其求值。

function getGenresId(genres){
    var genresArr = parseCSV(genres);
    Genre.find({name: {$in: genresArr } }, function (err, genres) {
        var genresId = genres.map(function (genre) {
            return genre.id;
        });
        return genresId.toString();
    });

}

async.parallel({
    getGenres: function (callback) {
        if(checkempty(req.query.genres) === true){
            callback(null, getGenresId(req.query.genres)});
        }
        else{
            callback(null, '');
        }

    },
    getActor: function (outercallback) {
        if(checkempty(req.query.actors) === true) {
            //other code here
        }
        else{
            outercallback(null, '');
        }
    }
);

I do understand that the function getGenresId() contains a blocking call to the database and Node.js will process it asynchronously. 我确实知道函数getGenresId()包含对数据库的阻塞调用,并且Node.js将异步处理它。 But is there a way I could force the 但是有没有办法我可以强迫

callback(null, getGenresId(req.query.genres)});

to evaluate the getGenresId function and wait for it to return a value before proceeding. 评估getGenresId函数并在继续之前等待它返回一个值。 I could use async's series function here but is there a native/better way to do this ? 我可以在这里使用异步的系列函数,但是有本机/更好的方法吗?

Using Q for node.js, you can return a promise from your getGenresId function, wait for it to be resolved and then call callback once it's resolved: 使用Q for node.js,您可以从getGenresId函数返回一个诺言,等待其解决,然后在解决后调用callback

var Q = require('q');
function getGenresId(genres){
    var deferred = Q.defer(); // creating the promise
    var genresArr = parseCSV(genres);
    Genre.find({name: {$in: genresArr } }, function (err, genres) {
        var genresId = genres.map(function (genre) {
            return genre.id;
        });
        deferred.resolve(genresId.toString()); // resolving the prmoise
    });   
    return deferred.promise; // returning the promise
}

async.parallel({
    getGenres: function (callback) {
        if(checkempty(req.query.genres) === true){
            //waiting for the promise
            getGenresId(req.query.genres).then(function(data) { 
                callback(null, data);
            });

        }
        else{
            callback(null, '');
        }
  ....

The problem is the following assumption: 问题是以下假设:

I do understand that the function getGenresId() contains a blocking call to the database 我知道函数getGenresId()包含对数据库的阻塞调用

...Because getGenresId is not blocking at all. ...因为getGenresId根本没有阻塞。 It returns undefined immediately (line #9) and then eventually runs a query on your database. 它立即返回undefined (第9行),然后最终在数据库上运行查询。 It doesn't block anything else from running, so it's non-blocking . 它不会阻止其他任何东西运行,所以它是非阻止的

Could you change the database call to be blocking? 您可以将数据库调用更改为阻止吗? Somewhat ( async-await , generators ), but don't bother, because you're nearly there with your existing code. 有点( async-awaitgenerators ),但是不要打扰,因为您的现有代码已经差不多了。 It only needs a small change to work: 它只需要很小的改动就可以工作:

// This function has a new argument, one named 'callback'.
function getGenresId(genres, callback){
    var genresArr = parseCSV(genres);
    Genre.find({name: {$in: genresArr } }, function (err, genres) {
        if(err) {
            callback(err);
            return; // Stop processing the rest of the function.
        }
        var genresId = genres.map(function (genre) {
            return genre.id;
        });
        // Instead of the `return` statement, we call the callback.
        callback(null, genresId.toString());
    });

}

async.parallel({
    getGenres: function (callback) {
        if(checkempty(req.query.genres) === true){
            // Call the function by passing the list of 
            // genres & this function's callback.
            // Functions are ordinary values.
            getGenresId(req.query.genres, callback);
        }
        else{
            callback(null, '');
        }

    },
...

See how the callback (which is passed to the getGenresId function) is called only after the result of your database are in? 看看仅在数据库结果输入getGenresId callback (传递给getGenresId函数)吗? That's the way to do it. 这就是这样做的方式。 The value of the return statement that you had ( return genresId.toString(); ), because it was inside of a non-blocking & asynchronous function (the database call), was discarded. 您拥有的return语句的值( return genresId.toString(); ),因为它位于非阻塞和异步函数(数据库调用)中,因此被丢弃。

Other options (promises, generators, etc) are valid approaches too, but there's nothing wrong with the async module that you're using already. 其他选项(承诺,生成器等)也是有效的方法,但是您已经在使用的async模块没有任何问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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