首先,抛出我们的需求:
实现一个函数,在多次异步请求全部结束之后再进行处理,即使有一次或多次失败,在失败时我们可以处理这些失败的情况,但是不会阻塞其它请求
我们首先想到的是 Promise.all:
function settle (promises) {return Promise.all(promises).then(res => {}).catch(err => {}) // 若其中的一个失败则会走catch}
Promise.all()可以在多次异步请求之后再处理其他的请求,
但是,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)})//输出 res 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 = 0let 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' } ]
