Node.js - 函数调用返回未定义并稍后求值

Node.js - Function call returning undefined and evaluated later

我正在使用异步模块并行执行一组函数。但是我在这些函数的回调中使用了另一个函数的 return 值。但问题是,函数 returns as undefined as callback 不会等待它被评估。

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 函数并等待它 return 一个值,然后再继续。我可以在这里使用 async 的系列函数,但是有 native/better 方法来做到这一点吗?

对 node.js 使用 Q,您可以 return 来自 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, '');
        }
  ....

问题是以下假设:

I do understand that the function getGenresId() contains a blocking call to the database

...因为 getGenresId 根本没有阻塞。它 returns 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 语句的值 (return genresId.toString();),因为它在非阻塞和异步函数(数据库调用)中,被丢弃了。

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