Использование Async / Awaits в пределах обещания - PullRequest
0 голосов
/ 03 июля 2018

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

  myPromise()
    .then(getStuffFromDb)
    .then(manipulateResultSet)
    .then(manipulateWithAsync)
    .then(returnStuffToCaller)

Теперь, в моем манипулируем WithAsync Я пытаюсь улучшить свой набор результатов, снова вызывая БД, но он не работает, как я ожидал, так как во время отладки я выяснил, что управление переходит к следующей функции returnStuffToCaller

Вот идея того, что входит в мою манипулировать с помощью функции :

function manipulateWithAsync(rs) {
  return rs.map( async function whoCares(singleRecord) {
      let smthUseful = await getMoreData(singleRecord.someField);
      singleRecord.enhancedField = smthUseful;
      return singleRecord;
  })
}

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

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

Спасибо!

Ответы [ 3 ]

0 голосов
/ 03 июля 2018

Итератор rs.map переходит к следующему элементу без ожидания в каждой отдельной итерации. Вам нужно что-то вроде asyncMap Вы можете использовать - https://github.com/caolan/async или реализовать себя

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

* функция cb должна быть асинхронной

0 голосов
/ 03 июля 2018

Оберните вашу карту с помощью Promise.all, верните Promise, затем await для результатов, где бы вы ни назвали manipulateWithAsync.

// MOCKS FOR DEMO
// Test data used as input for manipulateWithAsync
const testData = [
  { recordNumber: 1 },
  { recordNumber: 2 },
  { recordNumber: 3 }
];

// Mock function which returns Promises which resolve after random delay ranging from 1 - 3 seconds
const getMoreData = () =>
  new Promise(resolve => {
    const calledAt = Date.now();
    setTimeout(() => {
      resolve({
        usefulData: `Promise called at ${calledAt}`
      });
    }, Math.floor(Math.random() * 3000) + 1000);
  });

// SOLUTION / ANSWER
const manipulateWithAsync = async rs =>
  Promise.all(
    rs.map(async singleRecord => {
      const smthUseful = await getMoreData(singleRecord.someField);

      // Instead of manipulating original data,
      // which might cause some unwanted side effects going forward,
      // instead return new objects
      return { ...singleRecord, enhancedField: smthUseful };
    })
  );

await manipulateWithAsync(testData);
0 голосов
/ 03 июля 2018

Проблема в использовании async / await с Array.map

Этот ответ должен помочь: https://stackoverflow.com/a/40140562/5783272

...