Как я могу ждать завершения асинхронного обратного вызова внутри синхронного цикла Javascript, прежде чем продолжить

1

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

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

mymongodbconnection.find({}).toArray(function(err, documents) {
if (!err && documents.length !== 0) {
  documents.forEach(function(document) {

      if( someCheckPerformed(document)){
        console.log('keeping');
      }else{
        console.log('removing');
mymongodbconnection.remove({_id:document._id},fun(err,result){});
      }
  });

 notifyAdminAboutChange();
} else {
  logger.warn('No existing UA docs to filter');
}
});

Теперь, как вы можете видеть, мне нужно вызвать notifyAdminAboutChange(); только после того, как цикл for завершил итерацию по всем документам и удалил документы, которые необходимо удалить.

Мои вопросы:

  1. Могу ли я заблокировать выполнение цикла цикла, чтобы дождаться завершения удаления?
  2. Если 1 невозможно, то как мне достичь этого варианта использования?
  • 0
    Ответ, вероятно, состоит в том, чтобы использовать обещания и обещание-делать-пока ... но что такое mongodBCollectionInstance? Также вам может понадобиться использовать writeConcern с функцией удаления для Mongo.
  • 0
    Вы не можете заставить Javascript "ждать". Вместо этого вы должны либо изменить структуру вашего цикла, чтобы упорядочить асинхронные операции, либо запустить их все и отслеживать, когда все они выполняются с помощью чего-то вроде Promise.all() . Несколько связанных ответов: Как синхронизировать последовательность обещаний? и асинхронная функция внутри цикла JavaScript для
Теги:
callback

2 ответа

0
Лучший ответ

Используйте обещания - создайте один для каждого документа для удаления, а затем дождитесь их разрешения (используя Promise.all) перед вызовом вашей функции.

mongodBCollectionInstance.find({}).toArray(function(err, documents) {
  if (!err && documents.length !== 0) {
    var promises = [];

    documents.forEach(function(document) {
      if( someCheckPerformed(document)){
        console.log('keeping');
      }else{
        console.log('removing');
        promises.push(new Promise(function (fulfill, reject){
          mongodBCollectionInstance.remove(
            {_id:document._id},
            function (err, result) {
              fulfill();
            });
        }))
      }
    });
    Promise.all(promises).then(function () {
      notifyAdminAboutChange();
    });
  } else {
    logger.warn('No existing UA docs to filter');
  }
});
  • 0
    Эй, Грэг, спасибо, что помогли мне. Быстрый вопрос: если я позвоню выполнить одно обещание и отклонить другие, будет ли Promises.all по-прежнему вызываться или все обещания должны быть выполнены, чтобы Promises.all был вызван?
0

Я не знаю каких-либо JS-бит рук, чтобы легко закрепить в вашей существующей структуре, но если вы немного измените порядок и оставите свой разум открытым для рекурсивного решения, вы можете достичь желаемого результата:

coll.find({}).toArray((err, docs)=> {
    (function checkDoc(i){
        if(i >= docs.length) return;
        else if(pred(docs[i])) checkDoc(i + 1);
        else coll.remove({_id: docs[i]._id}, _=> checkDoc(i + 1));
    })(0);
})

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

демонстрация

Ещё вопросы

Сообщество Overcoder
Наверх
Меню