Как правильно связывать асинхронные функции в Node.js? - PullRequest
1 голос
/ 01 марта 2012

У меня есть интересный случай, когда мне нужно выполнить несколько запросов в MongoDB с использованием Mongoose, но ответ возвращается до того, как я могу завершить все из них.

У меня есть два типа документов: список и элемент.В одном конкретном вызове мне нужно получить все списки для конкретного пользователя, затем выполнить итерацию по каждому из них, извлечь все элементы и добавить их в соответствующий список перед возвратом.

List.find({'user_id': req.params.user_id}, function(err, docs){
  if (!err) {
    if (docs) {

      var results = [];

      _und.each(docs, function(value, key) {

        var list = value.toObject();
        list.items = [];

        Item.find({'list_id': value._id}, function(err, docs) {
          if (!err) {
            _und.each(docs, function(value, key) { list.items.push(value.toObject()); });
            results.push(list);
          }
          else {
            console.log(err);
          }
        });
      });

      res.send(results);

(_und - это то, как я импортировал underscore.js)

Очевидно, что проблема в обратных вызовах, и, поскольку существует несколько циклов, я не могу вернуться в обратном вызове.

Возможно, это тот случай, когдаМне нужно заранее подсчитать счет и проверять его на каждой итерации, чтобы решить, когда возвращать результаты.Это не кажется элегантным.

Ответы [ 2 ]

2 голосов
/ 01 марта 2012

Решение кода

Прежде всего, проблема с кодом.Отправка результатов до завершения запросов Item.find.Вы можете легко это исправить

var count = docs.length + 1;
next()
_und.each(docs, function(value, key) {

    var list = value.toObject();
    list.items = [];

    Item.find({
        'list_id': value._id
    }, function(err, docs) {
        if (!err) {
            _und.each(docs, function(value, key) {
                list.items.push(value.toObject());
            });
            // push asynchronous
            results.push(list);
            next()
        }
        else {
            console.log(err);
        }
    });
});

function next() {
    --count === 0 && finish()
}

function finish() {
    res.send(results)
}​

Самый простой способ - это подсчет ссылок, по умолчанию вы рассчитываете количество документов.Затем каждый раз, когда вы заканчиваете получать предмет, вы звоните next и уменьшаете счет на единицу.

Как только вы закончили получать все предметы, ваш счет должен быть равен нулю.Обратите внимание, что мы делаем .length + 1 и немедленно вызываем next.Это оправдывает случай, когда нет документов, которые в противном случае ничего бы не делали.

Решение для базы данных

Лучшее решение - правильно использовать монго.Вы не должны делать то, что фактически является соединением в вашем коде, это чертовски медленно и неэффективно.Вы должны иметь вложенный документ и денормализовать свой список.

так что list.items = [Item, Item, ...]

В качестве еще одного исключения, избегайте мангустов, это неэффективно, используйте собственный драйвер монго.

1 голос
/ 01 марта 2012

Я использую с этим модулем: https://github.com/caolan/async

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...