题目
同时并发十个AJAX请求,如果捕获错误不超过三次就返回所有数据,超过三次返回错误,应该怎么设计?
思考
因为是并发,首先想到Promise.all,但是这个是捕获到错误就不朝下走了,我们是否可以在捕获错误没超过三次的时候,强制朝下走呢?
如果不用Promise.all,我们是不是可以自己写一个捕获三次错误才返回的变异版Promise.all?
方案一
我们知道新的跨网络异步获取资源——fetch,这个API本身返回的就是Promise,非常方便后续处理,所以我们在这采用这个新接口。
第一个考虑的方案是即使捕获到错误了,没超过三次,就强行走下去。这个“强行走下去”其实说白了就是不reject而是继续resolve
const _fetch = (function(){
// 错误累计
let errorCount = 0
return (url,data = {}) => {
return fetch.post(url,data).then( res => {
// 成功之后,还是要返回一个promise对象,因为Promise.all只接收Promise实例
return Promise.resolve(res)
}).catch( err => {
// 捕获到错误的时候,因为使用闭包,所以错误数可以累加
errorCount++
// 如果没有超过3次,强行resolve,不中断Promise.all,超过直接返回错误中断
if(errorCount===3) {
Promise.reject(err)
} else {
Promise.resolve(err)
}
})
}
}())
// 调用
Promise.all([
_fetch('/a'),
_fetch('/b'),
]).then(res => {
console.log(res)
})
方案二
promise.all内部是捕获一次就中断,我们可以自己重新定义一个类似的方法,使之三次(或自定义次数)之后再中断
const _promiseAll = function(list) {
// promise.all最后返回的还是一个Promise实例
return new Promise((reslove, reject) => {
let value = [] // 返回数据
let count = 0 // 返回数据累计
let errorCount = 0 // 错误累计
for(let [i, p] of list.entries) {
// 以防万一,实例化list项
Promise.resolve(p).then(res => {
value[i] = res
count ++
// 如果全部走完,返回数据
if(count === list.length) resolve(values)
}).catch(err => {
errorCount ++
// 如果错误累计没到3次,依然定义数据,超出三次直接返回错误
if(errorCount <= 3) {
value[i] = err
} else {
reject(err)
}
})
}
})
}
// 调用
_promiseAll([
fetch('/a'),
fetch('/b'),
]).then(res => {
console.log(res)
})
以上是两种方案的思考,有待实际验证。