Использование Async / Awaits в обещании

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

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

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

вот представление о том, что находится в моей функции манипулироватьWithAsync:

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

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

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

Спасибо!

return Promise.all(rs.map(...)), но это может помочь return что-то из вашей функции карты, иначе вы собираетесь разрешить массив, заполненный undefined
Patrick Roberts 03.07.2018 11:13

да человек, я явно что-то возвращаю на своей карте. я написал код на лету при создании сообщения, спасибо, что указали, собираюсь редактировать сразу

Koop4 03.07.2018 11:19

Но, как указал @PatrickRoberts, вам нужно иметь Promise.all, иначе обещание разрешится с массивом, возвращаемым manipulateWithAsync.

Thiago Barcala 03.07.2018 11:22

Подтверждено, только что изменил мой код, и он работает правильно. @ Патрик, если вы можете создать ответ, я был бы рад его одобрить.

Koop4 03.07.2018 11:23
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
4
205
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

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

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

да, мой вопрос на самом деле дубликат

Koop4 03.07.2018 11:26

В этом случае можно использовать Promise.map(arr, fn).

Benjamin Gruenbaum 03.07.2018 14:31

Итератор 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 должна быть асинхронной

Это тоже работает, я думаю, что проще было бы использовать forEach вместо карты. Спасибо!

Koop4 03.07.2018 11:26

Оберните свою карту 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);

Другие вопросы по теме