javascript - 通过使用 async/await 模拟 .reduce() 来循环异步调用
问题描述
代码中使用的变量和函数:
const fakeAPI = (delay, value) =>
new Promise(resolve => setTimeout(() => resolve(value), delay));
const useResult = x => console.log(new Date(), x);
此代码通过使用 reduce() 实现来打印 forEach 不能使用异步调用的内容:
const forEachAsync = (arr, fn) =>
arr.reduce(
(promise, value) => promise.then(() => fn(value)),
Promise.resolve()
);
(async () => {
console.log("START FOREACH VIA REDUCE");
await forEachAsync([1, 2, 3, 4], async n => {
const x = await fakeAPI(n * 1000, n);
useResult(x);
});
console.log("END FOREACH VIA REDUCE");
})();
输出
/*
START FOREACH VIA REDUCE
2019-10-13T20:02:23.437Z 1
2019-10-13T20:02:24.446Z 2
2019-10-13T20:02:25.949Z 3
2019-10-13T20:02:27.952Z 4
END FOREACH VIA REDUCE
*/
arr.reduce
在主代码块的上下文中,函数中的 promise 和 value 参数的目的是什么?
是否将value参数传递给async n箭头函数?
尽管如此,我更喜欢解释,因为我正在研究功能程序,但是,如果有任何其他方式以 FP 方式处理这个问题,我将不胜感激。
解决方案
为每个
forEach
是您正在学习的代码不好的副作用。该示例使用async
and await
so.reduce
来链接.then
调用是没有意义的。也就是说,如果您想体验它的使用痛苦,我们可以实现它 -
async function forEach (arr, fn)
{ for (const x of arr)
await fn(x) // <- return value of fn disappears
}
const sleep = ms =>
new Promise(r => setTimeout(r, ms))
const fakeApi = x =>
sleep(1000).then(_ => `api response: ${x * x}`)
forEach
( [1,2,3,4]
, async x =>
// side effect tangled with task processing code
console.log((new Date).toUTCString(), await fakeApi(x))
)
.then(console.log, console.error) // <- no values beyond this point
"Sat, 30 Jan 2021 16:46:35 GMT" "api response: 1" // <- :35
"Sat, 30 Jan 2021 16:46:36 GMT" "api response: 4" // <- :36
"Sat, 30 Jan 2021 16:46:37 GMT" "api response: 9" // <- :37
"Sat, 30 Jan 2021 16:46:38 GMT" "api response: 16" // <- :38
undefined
要解决上述问题,请注意如何serial
和parallel
(下文)将数据包含在console.log
Promise 中,而不是使用诸如or之类的副作用推出值useResult
。
串行
我们可以按顺序编写哪些serial
进程任务-
async function serial (arr, fn)
{ let r = []
for (const x of arr)
r.push(await fn(x))
return r
}
const sleep = ms =>
new Promise(r => setTimeout(r, ms))
const fakeApi = x =>
sleep(1000).then(_ => `api response: ${x * x}`)
serial
( [1,2,3,4]
, async x => [ (new Date).toUTCString(), await fakeApi(x) ]
)
.then(console.log, console.error)
[
[
"Sat, 30 Jan 2021 16:39:04 GMT", // <- :04
"api response: 1"
],
[
"Sat, 30 Jan 2021 16:39:05 GMT", // <- :05
"api response: 4"
],
[
"Sat, 30 Jan 2021 16:39:06 GMT", // <- :06
"api response: 9"
],
[
"Sat, 30 Jan 2021 16:39:07 GMT", // <- :07
"api response: 16"
]
]
平行
或者我们可以编写parallel
哪些并行处理任务-
const parallel = (arr, fn) =>
Promise.all(arr.map(v => fn(v)))
const sleep = ms =>
new Promise(r => setTimeout(r, ms))
const fakeApi = x =>
sleep(1000).then(_ => `api response: ${x * x}`)
parallel
( [1,2,3,4]
, async x => [ (new Date).toUTCString(), await fakeApi(x) ]
)
.then(console.log, console.error)
[
[
"Sat, 30 Jan 2021 16:40:47 GMT", // <- :47
"api response: 1"
],
[
"Sat, 30 Jan 2021 16:40:47 GMT", // <- :47
"api response: 4"
],
[
"Sat, 30 Jan 2021 16:40:47 GMT", // <- :47
"api response: 9"
],
[
"Sat, 30 Jan 2021 16:40:47 GMT", // <- :47
"api response: 16"
]
]
推荐阅读
- sql - 向 SQL Server 添加一行 - 接收无效的对象名称
- lua - Avatar 检查脚本始终返回“Instance”
- python - 为多个组件制作 Python 类的最佳方法?,例如 Chromatograpy
- php - 在PHP中查找数组中最大值的键
- android - Android Studio Button onClick Listener 不起作用
- group-by - 如何按天计算所有结果
- mysql - ORDER BY 中的索引位置(排名位置)
- opentok - OpenTok/Vonage Video API 中的主要发言人
- javascript - PDF Decoded Base64 PDF 可以用 chrome 和浏览器打开,但不能用 adobe
- amazon-web-services - 在 AWS 路由 53 上购买了一个域,并且该域已注册给其他人