Задержка асинхронных вызовов в цикле - PullRequest
4 голосов
/ 04 ноября 2019

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

const myFunc = async (customers) => {
  const customerList = customers.map(async (customer) => {
    const cashCollected = await knex('cash_collections')
      .sum('amount_collected as amount')
      .where('account_code', customer.code)
      .first();
    const orderValue = await knex('orders')
      .sum('discounted_price as amount')
      .where('customer_id', customer.id)
      .first();
    const customerData = {
      name: customer.name,
      outstandingBalance: (orderValue.amount - cashCollected.amount),
    };
    // This line works after console.log(customerList);
    console.log(customerData);
    return customerData;
  });
   // console and return works before data is retrieved 
   // (before console.log(customerData) is run)
  console.log(customerList);
  return customerList;
};

// Function is called in another place
myFunc()

Ответы [ 2 ]

5 голосов
/ 04 ноября 2019

Вы делаете все эти вызовы параллельно, выполняя их в обратном вызове map. Если вы действительно хотите это сделать, вам нужно дождаться завершения этих вызовов, используя Promise.all:

const customerList = await Promise.all(customers.map(async (customer) => {
    // ...
}));

Если вы хотите сделать это последовательно, используйте цикл for и ждитекаждый ответ. :-) Но похоже, что параллель это нормально.

0 голосов
/ 04 ноября 2019

Вам нужно await карту, и тогда она будет ждать ее, в противном случае асинхронность не заставляет ее ждать, это фактически означает, что будет переходить к следующему коду, если вы не скажете await. вот так: const customerList = await customers.map.... Теперь, так как карта не возвращает обещание, вам нужно будет заключить его в обещание либо с Promise.all, либо с индивидуальным обещанием.

...