如何设计一个promise.all?

Promise.all原理

官网:Promise.all() 方法接收一个 promise 的 iterable 类型(注:Array,Map,Set 都属于 ES6 的 iterable 类型)的输入,并且只返回一个Promise实例,那个输入的所有 promise 的 resolve 回调的结果是一个数组。这个Promise的 resolve 回调执行是在所有输入的 promise 的 resolve 回调都结束,或者输入的 iterable 里没有 promise 了的时候。它的 reject 回调执行是,只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且 reject 的是第一个抛出的错误信息。

在实现之前我们先弄清楚promise.all的特点

  let fn1 = new Promise((resolve, reject) => {
    throw('fn1出错了')
  })
  let fn2 = new Promise((resolve, reject) => {
    reject('fn2出错了')
  })
  let fn3 = new Promise((resolve, reject) => {
    resolve('fn3成功了')
  })
  let fn4 = new Promise((resolve, reject) => {
    resolve('fn4成功了')
  })
  let fn5 = '我是fn5'
  Promise.all([fn4, fn3, fn5]).then(res => {
    console.log(res)  //  ['fn3成功了', 'fn4成功了', '我是fn5']
  }).catch(err => {
    console.log(err)
  })
  Promise.all([fn1, fn2, fn3, fn4, fn5]).then(res => {
    console.log(res)
  }).catch(err => {
    console.log(err)  // fn1出错了
  })

看到上面的demo,我们至少可以得出下面几个结论:

  1. Promise.all()生成的对象的状态是由数组中的Promise对象[fn1, fn2, fn3, fn4, fn5]决定的;当每个promise对象的状态为resolve的时候,fn3, fn4, fn5三个Promise对象产生的结果会组成一个数组返回返回给Promise.all生成的对象
  2. 如果fn1, fn2, fn3, fn4, fn5中有一个Promise对象变为rejected状态的话,romise.all生成的对象也会变成rejected状态,第一个被rejected的对象的返回值会被返回出来

如何自己实现一个promise.all呢

  function isPromise(val){
    return val && typeof val.then ==='function'
  }
  function promiseAll (promises) {
    return new Promise((resolve, reject) => {
      let result = []
      let flag = 0
      function next() {
        let newFn = promises.slice(flag, flag + 1)[0]
        carry(newFn, flag++)
      }
      next()
      function carry (fn, i) {
        // 判断fn是否是Promise对象
        let f = isPromise(fn) ? fn : Promise.resolve(fn)
        f.then(res => {
          result[i] = res
          // 如果全部是resolve状态,那就resolve出去result
          if (flag === promises.length) {
            return resolve(result)
          }
          next()
        }).catch(err => {
          return reject(err) //有异常直接reject出来
        })
      }
    })
  }
  promiseAll([fn3, fn4, fn5]).then(res => {
    console.log(res)  //  ['fn3成功了', 'fn4成功了', '我是fn5']
  }).catch(err => {
    console.log(err)
  })
  promiseAll([fn3, fn4, fn2, fn5]).then(res => {
    console.log(res)
  }).catch(err => {
    console.log(err) // fn2出错了
  })

以上就是实现promise.all的全部代码,我们实际开发中经常会碰到另外一个需求:
同时执行后端的多个接口,不管成功与否都要对应的返回出来,那么该怎么做呢?

function promiseAll (promises) {
  let results = [];
  let promiseCount = 0; // 用来计算参数中有没有被执行完
  let len = promises.length;
  return new Promise((resolve ,reject) => {
    promises.forEach((item, index) => {
      item.then(res => {
        results[index] = res
        promiseCount++
        if(promiseCount === len){
          resolve(results)
        }
      }).catch(err => {
        results[index] = err
        promiseCount++
        if(promiseCount === len){
          resolve(results)
        }
      })
    })
  })
}

总结

  1. 始终围绕Promise.all几个特点解读

    • Promise.all()接受一个 Array 类型的参数
    • 只有数组中全部的 Promise 都变为 resolve 的时候,返回一个新的 Promise 实例
    • 只要有一个失败,状态就变成 rejected
  2. 同时当面试官问你如何实现promise.all的时候,你可以把上面这两种情况都表达出来,面试官会眼前一亮,觉得你思维很缜密,可以加分不少哦

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值