Here is a function to build db queries:
const buildDbQueries = async elements => elements.reduce(
async (acc, element) => {
// wait for the previous reducer iteration
const { firstDbQueries, secondDbQueries } = await acc
const asyncStuff = await someApi(element)
// leave if the API does not return anything
if (!asyncStuff) return { firstDbQueries, secondDbQueries }
// async db query, returns a Promise
const firstDbQuery = insertSomethingToDb({
id: asyncStuff.id,
name: asyncStuff.name
})
// another async db query, returns a Promise
// have to run after the first one
const secondDbQuery = insertAnotherthingToDb({
id: element.id,
name: element.name,
somethingId: asyncStuff.id
})
return {
firstDbQueries: [...firstDbQueries, firstDbQuery],
secondDbQueries: [...secondDbQueries, secondDbQuery]
}
},
// initial value of the accumulator is a resolved promise
Promise.resolve({
firstDbQueries: [],
secondDbQueries: []
})
)
This function returns promises which should not be executed until they are resolved.
Now we use that function
const myFunc = async elements => {
const { firstDbQueries, secondDbQueries } = await buildDbQueries(elements)
// we don't want any query to run before this point
await Promise.all(firstDbQueries)
console.log('Done with the first queries')
await Promise.all(secondDbQueries)
console.log('Done with the second queries')
}
The problems are:
- the queries are executed before we call
Promise.all
. - the
firstDbQueries
queries are not executed before thesecondDbQueries
causing errors.
EDIT
As suggested in a comment, I tried not to use reduce
, but a for … of
loop.
const buildDbQueries = async elements => {
const firstDbQueries = []
const secondDbQueries = []
for (const element of elements) {
const asyncStuff = await someApi(element)
// leave if the API does not return anything
if (!asyncStuff) continue
// async db query, returns a Promise
const firstDbQuery = insertSomethingToDb({
id: asyncStuff.id,
name: asyncStuff.name
})
// another async db query, returns a Promise
// have to run after the first one
const secondDbQuery = insertAnotherthingToDb({
id: element.id,
name: element.name,
somethingId: asyncStuff.id
})
firstDbQueries.push(firstDbQuery)
secondDbQueries.push(secondDbQuery)
}
return { firstDbQueries, secondDbQueries }
}
This still produces the exact same problems as the previous version with reduce
.