Using Async / Awaits within promise


Using Async / Awaits within promise



I have a certain promise chain in my code that looks like this:


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



Now, in my manipulateWithAsync I'm trying to enhance my result set by calling the DB again, but it's not working as I expected, since while debugging i figured out the control moves to the next function which is the returnStuffToCaller



here's an idea of what's into my manipulateWithAsync function:


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



I get the point of this behaviour: the map function does work as expected and the promise chain doesn't give a duck about it since it's not working with the awaits.
Is there a way to allow my returnStuffToCaller function to wait till the async function did his job?



I also use bluebird and i tried to use coo-routine, so if you thing that it's a good solution I'll post my bluebird coo-routine failing code :)



Thanks!





return Promise.all(rs.map(...)) but it might help to return something from your map function, otherwise you're going to resolve with an array filled with undefined
– Patrick Roberts
Jul 3 at 9:13



return Promise.all(rs.map(...))


return


undefined





yeah man, i clearly return something in my map. i wrote the code on the fly while creating the post, thanks for pointing out, gonna edit right away
– Koop4
Jul 3 at 9:19





But as @PatrickRoberts pointed out, you need to have Promise.all, otherwise the promise resolves with the array returned by manipulateWithAsync.
– Thiago Barcala
Jul 3 at 9:22



Promise.all


manipulateWithAsync





Confirmed, just modified my code and it works properly. @Patrick if you can create an answer i'd be happy to approve it.
– Koop4
Jul 3 at 9:23




3 Answers
3



The problem is in using async/await with Array.map


Array.map



This answer should help: https://stackoverflow.com/a/40140562/5783272





yep, my question is actually a duplicate
– Koop4
Jul 3 at 9:26





In this case Promise.map(arr, fn) can be used
– Benjamin Gruenbaum
Jul 3 at 12:31


Promise.map(arr, fn)



rs.map iterator jumps to the next element without waiting in each separate iteration.
You need something like asyncMap
You can use - https://github.com/caolan/async
or either implement yourself


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



*cb function must be async one





This one works too, I think an easier change would be to use forEach over map. Thanks!
– Koop4
Jul 3 at 9:26





Bluebird already comes with Promise.map though
– Benjamin Gruenbaum
Jul 3 at 12:31


Promise.map



Wrap your map with Promise.all return the Promise then await for the results wherever you call the manipulateWithAsync.


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);






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

api-platform.com Unable to generate an IRI for the item of type

How to set up datasource with Spring for HikariCP?

Display dokan vendor name on Woocommerce single product pages