这是构建数据库查询的功能:
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: []
})
)
此函数返回的promise必须在解决后才能执行。
现在我们使用该功能
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')
}
问题是:
Promise.all
之前执行查询。firstDbQueries
查询不会在secondDbQueries
引起错误之前执行。 编辑
如评论中所建议,我尝试不使用reduce
,而是使用for … of
循环。
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 }
}
这仍然会产生与带有reduce
的先前版本完全相同的问题。
答案 0 :(得分:3)
请勿使用async
减速器。尤其是不要建立承诺。或一堆东西以后再运行。在许多级别上这都是错误的。
我想您正在寻找类似的东西
function buildDbQueries(elements) {
return elements.map(element =>
async () => {
const asyncStuff = await someApi(element)
// leave if the api doesn't return anything
if (!asyncStuff) return;
await insertSomethingToDb({
id: asyncStuff.id,
name: asyncStuff.name
});
return () =>
insertAnotherthingToDb({
id: element.id,
name: element.name,
somethingId: asyncStuff.id
})
;
}
);
}
async function myFunc(elements) {
const firstQueries = buildDbQueries(elements)
// we don't want any query to run before this point
const secondQueries = await Promise.all(firstQueries.map(query => query()));
// this call actually runs the query ^^^^^^^
console.log('Done with the first queries');
await Promise.all(secondQueries.map(query => query()));
// this call actually runs the query ^^^^^^^
console.log('Done with the second queries')
}