Возвращаемое значение из асинхронной функции в 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'); в последний обратный вызов функции.

Я также рекомендую вам проверить этот модуль узла. Это поможет вам легче создавать асинхронные / синхронные функции и позволит вам выполнить обратный вызов, когда все асинхронные функции будут завершены.

Другие вопросы по тегам