Как сделать вызов асинхронного метода внутри другого асинхронного метода `each` (NodeJS)? - PullRequest
2 голосов
/ 13 января 2012

Как сделать вызов асинхронного метода внутри другого асинхронного each метода (NodeJS)?

Конкретный пример - при работе с базой данных мне нужно удалить все записи.Но я не могу просто удалить всю коллекцию, мне нужно уничтожить каждую запись одну за другой, перед удалением мне нужно прочитать запись, выполнить некоторую бизнес-логику в приложении и только потом удалить ее.

Итакдавайте попробуем реализовать наш метод deleteAll (на самом деле это настоящий API из драйвера узла-mongodb):

deleteAll = function(selector, callback){
  collection.find(selector).each(function(err, doc){
    if(err){
      callback(err)
    }else{
      if(doc === null){
        // each returns null when there's no more documents, we are finished.
        callback(null)      
      }else{
        doSomeBusinessLogicBeforeDelete(doc)

        // How to delete it using asynchronous `remove` method?        
        collection.remove({_id: doc._id}, function(err){
          // What to do with this callback? 
          // And how to make `each` wait untill we 
          // deleting this record?
          ???
        })
      }      
    }
  })
}

На самом деле есть способ сделать это - использовать метод collection.nextObject вместоcollection.each, но я хочу знать, возможно ли это решить с помощью each или нет?Сейчас я считаю, что это невозможно, но, может быть, я ошибаюсь?

ОБНОВЛЕНИЕ: источник each метод:

Cursor.prototype.each = function(callback) {
  var self = this;

  if (!callback) {
    throw new Error('callback is mandatory');
  }

  if(this.state != Cursor.CLOSED) {
    process.nextTick(function(){
      // Fetch the next object until there is no more objects
      self.nextObject(function(err, item) {        
        if(err != null) return callback(err, null);

        if(item != null) {
          callback(null, item);
          self.each(callback);
        } else {
          // Close the cursor if done
          self.state = Cursor.CLOSED;
          callback(err, null);
        }

        item = null;
      });
    });
  } else {
    callback(new Error("Cursor is closed"), null);
  }
};

Ответы [ 3 ]

1 голос
/ 13 января 2012

Попробуйте что-то вроде этого.

deleteAll = function(selector, callback){
  // count all documents you need to fire remove for
  var count = collection.filter(function(doc) { return doc === null }).length,
          i = count;

  collection.find(selector).each(function(err, doc){
    if(err){
      callback(err)
    }else{
      if(doc === null){
        callback(null)      
      }else{
        doSomeBusinessLogicBeforeDelete(doc)

        collection.remove({_id: doc._id}, function(err){
          i--;
          if (i <= 0) callback('done');
        })
      }      
    }
  })
}
1 голос
/ 30 октября 2012

Итак, после пары месяцев работы с узлом, я получил ответ на свой вопрос, вот одна из возможных реализаций асинхронизации для каждого (могут быть и другие похожие, но с небольшими отличиями в обработке ошибок):

asyncEach(
  function(obj, next){
    // do something with obj
    // call next when You finish and want next object, 
    // You can also pass error into next in case of error.
    console.log(obj)
    next()
  },
  function(err){
    // Will be called when there's no more objects.
  }
)

Реализация each в монго отличается, с ней невозможно сделать правильную последовательную итерацию (может быть, это нормально, может быть, они имеют разные цели дизайна).

0 голосов
/ 13 января 2012

Хорошо, что вы написали, будет работать, хотя и не уверен насчет этой строки:

  if(doc === null){
    // each returns null when there's no more documents, we are finished.
    callback(null)  

Поскольку, я не знаю логику, но это будет работать.Технически функции не ждут, вы просто передаете другую функцию, которая будет выполнена после завершения работы.то, что делается, здесь асинхронно и параллельно.Вы также можете посмотреть асинхронную версию каждой и некоторых других функций в модуле async .

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