В моем коде есть определенная цепочка обещаний, которая выглядит так:
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 :)
Спасибо!
да человек, я явно что-то возвращаю на своей карте. я написал код на лету при создании сообщения, спасибо, что указали, собираюсь редактировать сразу
Но, как указал @PatrickRoberts, вам нужно иметь Promise.all, иначе обещание разрешится с массивом, возвращаемым manipulateWithAsync.
Подтверждено, только что изменил мой код, и он работает правильно. @ Патрик, если вы можете создать ответ, я был бы рад его одобрить.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Проблема в использовании async / await с Array.map
Этот ответ должен помочь: https://stackoverflow.com/a/40140562/5783272
да, мой вопрос на самом деле дубликат
В этом случае можно использовать Promise.map(arr, fn).
Итератор 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 вместо карты. Спасибо!
Оберните свою карту 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);
return Promise.all(rs.map(...)), но это может помочьreturnчто-то из вашей функции карты, иначе вы собираетесь разрешить массив, заполненныйundefined