Возвращаемое значение из асинхронной функции в Nodejs
Я использую nodejs для запроса данных из Mongodb через Mongoose. После получения данных я хочу что-то сделать с этими данными, прежде чем отвечать клиенту. Но я не могу получить возвращаемое значение. Посмотрев в Google, я узнал, что функции Node.js - это асинхронная функция JavaScript (без блокировки ввода / вывода). Я пытаюсь это сделать ( http://www.youtube.com/watch?v=xDW9bK-9pNY), но это не работает. Ниже мой код. MyObject оценивается внутри функции "find()" и не определяется вне функции "find()". Так что я должен сделать, чтобы получить данные? Спасибо!
var Person = mongoose.model('Person', PersonSchema);
var Product = mongoose.model('Product', ProductSchema);
var myObject = new Object();
Person.find().exec(function (err, docs) {
for (var i=0;i<docs.length;i++)
{
Product.find({ user: docs[i]._id},function (err, pers) {
myObject[i] = pers;
console.log(myObject[i]); //return the value is ok
});
console.log(myObject[i]); //return undefined value
}
console.log(myObject); //return undefined value
});
console.log(myObject); //return undefined value
app.listen(3000);
console.log('Listening on port 3000');
2 ответа
Причина, по которой вы получаете неопределенные значения, заключается в том, что функция поиска является асинхронной и может завершиться в любое время. В вашем случае это заканчивается после того, как вы используете console.log()
поэтому значения не определены при обращении к ним.
Чтобы решить эту проблему, вы можете использовать только значения внутри обратного вызова функции find. Это будет выглядеть примерно так:
var Person = mongoose.model('Person', PersonSchema);
var Product = mongoose.model('Product', ProductSchema);
var myObject = new Object();
function getData(docs, callback) {
function loop(i) {
Product.find({ user: docs[i]._id}, function (err, pers) {
myObject[i] = pers;
if (i < docs.length) {
loop(i + 1);
} else {
callback();
}
});
};
loop(0);
};
Person.find().exec(function(err, docs) {
getData(docs, function() {
// myObject has been populated at this point
});
});
Обработка данных была перемещена в цикл, который ожидает завершения предыдущей итерации. Таким образом, мы можем определить, когда сработал последний обратный вызов, чтобы запустить обратный вызов в функции-обертке.
Имейте в виду, что к моменту выполнения функций console.log запрос еще не завершен, поэтому будет отображаться "неопределенный". В этом суть асинхронности nodeJS.
Например,
Person.find().exec(function (err, docs) {
for (var i=0;i<docs.length;i++)
{
Product.find({ user: docs[i]._id},function (err, pers) {
myObject[i] = pers;
console.log(myObject[i]); //return the value is ok
});
console.log(myObject[i]); //return undefined value
}
console.log(myObject); //return undefined value
});
console.log(myObject); // <-- Initially, this value will be undefined. After some miliseconds (Or the duration of the .exec function, myObject will contain the results.
Если вы действительно хотите дождаться завершения запроса, чтобы использовать значения, я бы порекомендовал переместить app.listen(3000);
а также console.log('Listening on port 3000');
в последний обратный вызов функции.
Я также рекомендую вам проверить этот модуль узла. Это поможет вам легче создавать асинхронные / синхронные функции и позволит вам выполнить обратный вызов, когда все асинхронные функции будут завершены.