首先,抛出我们的需求:
实现一个函数,在多次异步请求全部结束之后再进行处理,即使有一次或多次失败,在失败时我们可以处理这些失败的情况,但是不会阻塞其它请求
我们首先想到的是 Promise.all:
function settle (promises) {
return Promise.all(promises)
.then(res => {})
.catch(err => {}) // 若其中的一个失败则会走catch
}
然鹅,Promise.all()其中的一个请求失败了就会走catch,此时无法满足请求全部结束的需求。
但是反过来想Promise.all()是需要所有的都成功才不会走catch,这样才不会影响处理其它请求的响应,这样我们就想,能不能让所有的promises都走resolve,把error的信息扔到resolve中。基于这个思路可以把所有的promise转成resolve,首先我们看要怎样将一个promise都转成resolve的处理:
const p2 = new Promise((res, reject) => {
setTimeout(() =>{
reject(2)
}, 2000)
})
let resolvePromise = p2.then(res => res).catch(err => err)
resolvePromise.then(res => {
console.log('res', res)
}).catch(err => {
console.log('err', err)
})
//输出 resolve 2
处理了单个,那么多个也是类似的,再结合Promise.all
let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
return promises.map(promise => {
return promise.then(res => res).catch(err => err)
})
}
let promiseArr = transferedPromises(promises)
Promise.all(promiseArr).then(resArr => {
console.log(resArr)
})
让我们验证一下:
const p1 = new Promise((res, rej) => {
setTimeout(() =>{
res(1)
}, 1000)
})
const p2 = new Promise((res, rej) => {
setTimeout(() =>{
rej('err 2')
}, 2000)
})
const p3 = new Promise((res, rej) => {
setTimeout(() =>{
res(3)
}, 3000)
})
let promises = [p1, p2, p3]
let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
return promises.map(promise => {
return promise.then(res => res).catch(err => err)
})
}
let promiseArr = transferedPromises(promises)
Promise.all(promiseArr).then(resArr => {
console.log(resArr)
})
// 输出 [ 1, 'err 2', 3 ]
至此我们实现了开始的需求,如果需要其它更多的信息,可以在then和catch的hanler中增加一些自己想要的,比如:
let thenHandler = function (res) {
return {
res: res,
status: 'success'
}
}
let catchHandler = function (err) {
return {
err: err,
status: 'failed'
}
}
let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
return promises.map(promise => {
return promise.then(thenHandler).catch(catchHandler)
})
}
好,我们处理了多次reject的情况,每次reject都可以拿得到reject具体的内容,再根据这些内容做些失败的提示了什么的。
然后,来了个需求:5(n)次异步请求最多允许失败2(m,m < n)次.
这个需求我们依然可以利用Promise.all()需要所有的promise都是resolve状态这个特性:在超过2(m, m < n)次时返回一个reject状态的promise,改造catchHandler:
let count = 2 // 最多失败次数
let errorCount = 0 // 失败的次数
let catchHandler = function (err) {
errorCount++
if (errorCount >= count) {
return Promise.reject(`catch 超过了${count}次`) // reject的内容可以自定义
} else {
return {
err: err,
status: 'failed'
}
}
}
整体扔到一个函数里就是:
const dealPromises = (promises, count) => {
let errorCount = 0
let thenHandler = function (res) {
return {
res: res,
status: 'success'
}
}
let catchHandler = function (err) {
errorCount++
if (errorCount >= count) {
return Promise.reject(`catch 超过了${count}次`)
} else {
return {
err: err,
status: 'failed'
}
}
}
let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
return promises.map(promise => {
return promise.then(thenHandler).catch(catchHandler)
})
}
let promiseArr = transferedPromises(promises)
Promise.all(promiseArr).then(resArr => {
console.log('来到了then', resArr)
}).catch(err => {
console.log('来到了catch', err)
})
}
dealPromises(promises, 3)
// 输出: 来到了catch catch 超过了3次
dealPromises(promises, 10)
// 输出: 来到了then [ { res: 1, status: 'success' },
// { err: 'err 2', status: 'failed' },
// { res: 3, status: 'success' },
// { err: 'err 4', status: 'failed' },
// { err: 'err 5', status: 'failed' },
// { res: 4, status: 'success' },
// { err: 'err 7', status: 'failed' } ]