Попытка вызвать несколько асинхронных функций и получить результат как undefined.

Пробовал async.waterfall, но не смог заставить его работать.

Код:

const pendingData = [];

async.waterfall([
    function (callback) {
      WaitForApproval.find({}, (err,result) => {
        callback(null,result);
      });
    },
    function (result, callback) {
      result.forEach(data => {
        User.findOne({_id: data.uploadedBy}, (err,name) => {
          let total = {
            id: data._id,
            name: name.name,
            subject: data.subject,
            uploadOn: data.uploadedAt
          };
          pendingData.push(total);
        });
      });
      callback(null,'done');
    }
  ], function (err,result) {
    if(result === 'done') {   
      console.log(pendingData); // it is giving empty result.
    }
  });

Как дождаться асинхронной функции?

1
Rupesh Yadav 13 Сен 2018 в 21:23

2 ответа

Лучший ответ

Проблема заключается в том, что вы выполняете асинхронные функции в неасинхронном цикле forEach.

У вас есть несколько вариантов здесь:

  1. Сделайте вызов mongoDB рекурсивно - оберните этот запрос в функцию, которая вызывает себя после возврата запроса.

  2. Прочтите о пакетных операциях mongoDB - https://docs.mongodb.com/manual/reference / метод / навалом /

  3. Используйте шаблон async / await с каждым вызовом, объявляя функцию обратного вызова внутри асинхронного водопада как async, а затем используя await внутри функции для каждого запроса. По умолчанию forEach не является асинхронным. Если вы все еще хотите использовать forEach, вы можете либо переписать его асинхронно (см. Ниже), либо использовать обычный цикл for:

async function asyncForEach(array, callback) {
  for (let index = 0; index < array.length; index++) {
    await callback(array[index], index, array)
  }
}

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

2
AlexanderGriffin 13 Сен 2018 в 18:47

Я бы посоветовал вам сразу добавить звонок на callback(null,'done'); pendingData.push(total);

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

Однажды у меня была аналогичная проблема асинхронного кода, работающего не в порядке, я хотел, поэтому я сделал небольшую настройку, используя настраиваемую функцию обещания (я раздумываю) и назвал ее порядком ... такая идея может решить вашу проблему, если вы можете ее применить к вашему коду правильно https://github.com/lalosh/Ideas/blob/master/promiseOrder. JS

2
Louay Alosh 13 Сен 2018 в 18:41