首先,抛出我们的需求:

实现一个函数,在多次异步请求全部结束之后再进行处理,即使有一次或多次失败,在失败时我们可以处理这些失败的情况,但是不会阻塞其它请求

我们首先想到的是 Promise.all:

  1. function settle (promises) {
  2. return Promise.all(promises)
  3. .then(res => {})
  4. .catch(err => {}) // 若其中的一个失败则会走catch
  5. }

Promise.all()可以在多次异步请求之后再处理其他的请求,

但是,Promise.all()其中的一个请求失败了就会走catch,此时无法满足请求全部结束的需求。

但是反过来想Promise.all()是需要所有的都成功才不会走catch,这样才不会影响处理其它请求的响应,这样我们就想,能不能让所有的promises都走resolve,把error的信息扔到resolve中。基于这个思路可以把所有的promise转成resolve,首先我们看要怎样将一个promise都转成resolve的处理:

  1. const p2 = new Promise((res, reject) => {
  2. setTimeout(() =>{
  3. reject(2)
  4. }, 2000)
  5. })
  6. let resolvePromise = p2.then(res => res).catch(err => err)
  7. resolvePromise.then(res => {
  8. console.log('res', res)
  9. }).catch(err => {
  10. console.log('err', err)
  11. })
  12. //输出 res 2

处理了单个,那么多个也是类似的,再结合Promise.all

  1. let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
  2. return promises.map(promise => {
  3. return promise.then(res => res).catch(err => err);
  4. })
  5. }
  6. let promiseArr = transferedPromises(promises);
  7. Promise.all(promiseArr).then(resArr => {
  8. console.log(resArr);
  9. })

让我们验证一下:

  1. const p1 = new Promise((res, rej) => {
  2. setTimeout(() =>{
  3. res(1)
  4. }, 1000)
  5. })
  6. const p2 = new Promise((res, rej) => {
  7. setTimeout(() =>{
  8. rej('err 2')
  9. }, 2000)
  10. })
  11. const p3 = new Promise((res, rej) => {
  12. setTimeout(() =>{
  13. res(3)
  14. }, 3000)
  15. })
  16. let promises = [p1, p2, p3]
  17. let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
  18. return promises.map(promise => {
  19. return promise.then(res => res).catch(err => err)
  20. })
  21. }
  22. let promiseArr = transferedPromises(promises);
  23. Promise.all(promiseArr).then(resArr => {
  24. console.log(resArr)
  25. })
  26. // 输出 [ 1, 'err 2', 3 ]

至此我们实现了开始的需求,如果需要其它更多的信息,可以在then和catch的hanler中增加一些自己想要的,比如:

  1. let thenHandler = function (res) {
  2. return {
  3. res: res,
  4. status: 'success'
  5. }
  6. }
  7. let catchHandler = function (err) {
  8. return {
  9. err: err,
  10. status: 'failed'
  11. }
  12. }
  13. let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
  14. return promises.map(promise => {
  15. return promise.then(thenHandler).catch(catchHandler)
  16. })
  17. }

好,我们处理了多次reject的情况,每次reject都可以拿得到reject具体的内容,再根据这些内容做些失败的提示了什么的。

然后,来了个需求:5(n)次异步请求最多允许失败2(m,m < n)次.
**
这个需求我们依然可以利用Promise.all()需要所有的promise都是resolve状态这个特性:在超过2(m, m < n)次时返回一个reject状态的promise,改造catchHandler:

  1. let count = 2 // 最多失败次数
  2. let errorCount = 0 // 失败的次数
  3. let catchHandler = function (err) {
  4. errorCount++
  5. if (errorCount >= count) {
  6. return Promise.reject(`catch 超过了${count}次`) // reject的内容可以自定义
  7. } else {
  8. return {
  9. err: err,
  10. status: 'failed'
  11. }
  12. }
  13. }

整体扔到一个函数里就是:

  1. const dealPromises = (promises, count) => {
  2. let errorCount = 0
  3. let thenHandler = function (res) {
  4. return {
  5. res: res,
  6. status: 'success'
  7. }
  8. }
  9. let catchHandler = function (err) {
  10. errorCount++
  11. if (errorCount >= count) {
  12. return Promise.reject(`catch 超过了${count}次`)
  13. } else {
  14. return {
  15. err: err,
  16. status: 'failed'
  17. }
  18. }
  19. }
  20. let transferedPromises = (promises) => { // 返回一个处理之后的promise数组
  21. return promises.map(promise => {
  22. return promise.then(thenHandler).catch(catchHandler)
  23. })
  24. }
  25. let promiseArr = transferedPromises(promises)
  26. Promise.all(promiseArr).then(resArr => {
  27. console.log('来到了then', resArr)
  28. }).catch(err => {
  29. console.log('来到了catch', err)
  30. })
  31. }
  32. dealPromises(promises, 3)
  33. // 输出: 来到了catch catch 超过了3次
  34. dealPromises(promises, 10)
  35. // 输出: 来到了then [ { res: 1, status: 'success' },
  36. // { err: 'err 2', status: 'failed' },
  37. // { res: 3, status: 'success' },
  38. // { err: 'err 4', status: 'failed' },
  39. // { err: 'err 5', status: 'failed' },
  40. // { res: 4, status: 'success' },
  41. // { err: 'err 7', status: 'failed' } ]

参考文档

https://zhuanlan.zhihu.com/p/37728714