javascript - 如何使用异步减速器来构建一系列承诺?
问题描述
这是一个构建数据库查询的函数:
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: []
})
)
此函数返回不应执行的承诺,直到它们被解决。
现在我们使用那个函数
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
。
解决方案
不要使用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')
}
推荐阅读
- javascript - 如何使 Chai 自定义断言失败?
- mysql - MySQL查询总时间,其中值等于“X”
- android - Android 应用操作不适用于语音命令
- .net - 获取物理处理器数量.NET Core 2.2
- .htaccess - 文件 .htaccess 和 css
- node.js - mongo DB中的多级聚合查找
- curl - 尝试下载 Hyperledger 示例的特定于平台的二进制文件时,“操作无法完成。应执行重试”
- java - CURRENCY - 仅当小数点超过 2 位时才舍入双精度值
- python - 如何找到列表中连续元素序列的总和?
- excel - 找出最后一个字符是字母还是数字