Node.js - 函数调用返回undefined并在以后进行评估

时间:2015-03-09 10:43:58

标签: javascript node.js mongodb asynchronous

我正在使用异步模块并行执行一组函数。但是我在这些函数的回调中使用了另一个函数的返回值。但问题是,函数返回未定义,因为回调不等待它被评估。

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, '');
        }
    }
);

我知道函数getGenresId()包含对数据库的阻塞调用,Node.js将异步处理它。但有没有办法强迫

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

评估getGenresId函数并等待它继续之前返回一个值。我可以在这里使用async的系列函数,但有没有本地/更好的方法来做到这一点?

2 个答案:

答案 0 :(得分:1)

使用Q作为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, '');
        }
  ....

答案 1 :(得分:1)

问题是以下假设:

  

我知道函数getGenresId()包含对数据库的阻塞调用

...因为getGenresId根本没有阻止。它立即返回undefined(第9行),然后最终在您的数据库上运行查询。它不会阻止任何其他操作,因此它是非阻塞

您可以将数据库调用更改为阻止吗?有点( async-awaitgenerators ),但不要打扰,因为你的现有代码几乎就在那里。它只需要一点点改变就可以了:

// 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, '');
        }

    },
...

了解如何在数据库结果出现后调用callback(传递给getGenresId函数)?这是做到这一点的方法。您拥有的返回语句的值(return genresId.toString();),因为它位于非阻塞&异步函数(数据库调用)被丢弃了。

其他选项(承诺,生成器等)也是有效的方法,但是您已经使用的async模块没有任何问题。