简单优雅的JavaScript代码片段文章系列:
简单优雅的JavaScript代码片段(一):异步控制
简单优雅的JavaScript代码片段(二):流控和重试
简单优雅的JavaScript代码片段(三):合并请求,成批发出
首个成功的Promise
从一组Promise里面得到第一个“成功的”结果,同时获得了并发执行的速度和容灾的能力。
Promise.race
不满足需求,因为如果有一个Promise率先reject,结果Promise也会立即reject;Promise.all
也不满足需求,因为它会等待所有Promise,并且要求所有Promise都成功resolve。
function firstSuccess(promises){
return Promise.all(promises.map(p => {
// If a request fails, count that as a resolution so it will keep
// waiting for other possible successes. If a request succeeds,
// treat it as a rejection so Promise.all immediately bails out.
return p.then(
val => Promise.reject(val),
err => Promise.resolve(err)
);
})).then(
// If '.all' resolved, we've just got an array of errors.
errors => Promise.reject(errors),
// If '.all' rejected, we've got the result we wanted.
val => Promise.resolve(val)
);
}
把resolve的Promise反转成reject,把reject的Promise反转成resolve,然后用Promise.all
合并起来。
这样的话,只要有一个原始Promise成功resolve,就会造成Promise.all
立刻被reject,实现提前退出!太巧妙了!
这个方法适合的场景:
- 有多条路可以走,其中任意一条路走通即可,其中有一些路失败也没关系
- 为了加速得到结果,并发地走多条路,避免瀑布式尝试
参考自 https://stackoverflow.com/a/37235274/8175856
2020年8月28日更新:现在它已经被新版浏览器原生实现:Promise.any
异步reduce
有时候业务逻辑要求我们必须串行地处理多个数据,不能像上面那样并发地处理多个数据。即,通过瀑布式的异步操作,将一个数组reduce成一个值。这个时候可以巧妙地使用array.reduce:
(async () => {
const data = [1, 2, 3]
const result = await data.reduce(async (accumP, current, index) => {
// 后面的处理要等待前面完成
const accum = await accumP;
const next = await apiCall(accum, current);
return next
}, 0);
console.log(result) // 6
async function apiCall(a, b) {
return new Promise((res)=> {
setTimeout(()=> {res(a+b);}, 300)
})
}
})()
与更常见的【array.map + Promise.all方案】对比:
(async () => {
const data = [1, 2, 3]
const result = await Promise.all(
data.map(async (current, index) => {
// 处理是并发的
return apiCall(current)
})
)
console.log(result)
async function apiCall(a) {
return new Promise((res) => {
setTimeout(() => {
res(a * 2)
}, 300)
})
}
})()
- 两个方案相同点:对每个数组项执行处理,并且其中任一次处理的失败都会造成整体失败
- reduce方案是瀑布式的,map方案是并发的
- reduce方案,当你处理到第n项的时候,你可以使用之前的累积量
参考自 https://stackoverflow.com/a/41243567/8175856
相关文章
本系列下一篇文章:【代码鉴赏】简单优雅的JavaScript代码片段(二):流控和重试
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。