我正在使用异步模块并行执行一组函数。但是我在这些函数的回调中使用了另一个函数的返回值。但问题是,函数返回未定义,因为回调不等待它被评估。
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的系列函数,但有没有本地/更好的方法来做到这一点?
答案 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-await
,generators
),但不要打扰,因为你的现有代码几乎就在那里。它只需要一点点改变就可以了:
// 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
模块没有任何问题。