手写promise.all()方法、promise.race()方法

317 阅读2分钟

Promise.all()描述

  • Promise.all的返回值是一个新的Promise实例
  • Promise.all接受一个可遍历的数据容器,容器中每个元素都应是Promise实例。容器可以定义为数组
  • 数组中每个Promise实例都成功时(由pendding状态转化为fulfilled状态),Promise.all才成功。这些Promise实例所有的resolve结果会按原来的顺序集合在一个数组中作为Promise.all的resolve的结果
  • 数组中只要有一个Promise实例失败(由pendding状态转化为rejected状态),Promise.all就失败。此时第一个被reject的实例的返回值,会传递给p的回调函数。

思路

  • Promise.all接受一个数组,返回值是一个新的Promise实例
Promise.MyAll = function(promise){
   return new Promise((resolve,reject)=>{})
}
  • 数组中所有Promise实例都成功,Promise.all才成功。需要一个数组收集这些Promise实例的resolve结果。万一数组里面有元素不是Promise,就需要用Promise.resolve()解决。Promise实例是不能直接调用resolve方法的,用.then()去收集结果
Promise.MyAll = function(promise){
   let arr = []
   return new Promise((resolve,reject)=>{
      promise.forEach((item,i)=>{
        Promise.resolve(item).then(res=>{
          arr[i] = res
        })
      })
   })
}
  • 将收集到的结果(数组arr)作为参数传给外层的resolve方法。
Promise.MyAll = function(promise){
   let arr = []
   count = 0 
   return new Promise((resolve,reject)=>{
      promise.forEach((item,i)=>{
        Promise.resolve(item).then(res=>{
          arr[i] = res
          count += 1
          if(count === promise.length)resolve(arr)
        })
      })
   })
}
  • 最后处理失败的情况,用.catch()方法捕获失败
Promise.MyAll = function(promise){
   let arr = []
   count = 0 
   return new Promise((resolve,reject)=>{
      promise.forEach((item,i)=>{
        Promise.resolve(item).then(res=>{
          arr[i] = res
          count += 1
          if(count === promise.length)resolve(arr)
        }).catch(reject)
      })
   })
}

总结

Promise.myAll = (promises) => { 
   return new Promise((rs, rj) => { 
       // 计数器 
       let count = 0 
       // 存放结果 
       let result = [] 
       const len = promises.length 
         if (len === 0) { 
              return rs([]) 
         } 
    promises.forEach((p, i) => { 
       // 注意有的数组项有可能不是Promise,需要手动转化一下 
             Promise.resolve(p).then((res) => {  
                 count += 1 
                 // 收集每个Promise的返回值 
                 result[ i ] = res 
                 // 当所有的Promise都成功了,那么将返回的Promise结果设置为result 
                 if (count === len) { rs(result) } 
                 // 监听数组项中的Promise catch只要有一个失败,那么我们自己返回的Promise也会失败 
              })
     .catch(rj) 
     }) 
   })
} 
// 测试一下 
const p1 = Promise.resolve(1) 
const p2 = new Promise((resolve) => { setTimeout(() => resolve(2), 1000) }) 
const p3 = new Promise((resolve) => { setTimeout(() => resolve(3), 3000) }) 
const p4 = Promise.reject('err4') 
const p5 = Promise.reject('err5')

// 1. 所有的Promise都成功了 
const p11 = Promise.myAll([ p1, p2, p3 ]) 
           .then(console.log) // [ 1, 2, 3 ] 
           .catch(console.log) 
// 2. 有一个Promise失败了 
const p12 = Promise.myAll([ p1, p2, p4 ]) 
           .then(console.log) 
           .catch(console.log) // err4 
// 3. 有两个Promise失败了,可以看到最终输出的是err4,第一个失败的返回值 
const p13 = Promise.myAll([ p1, p4, p5 ]) 
           .then(console.log) 
           .catch(console.log) // err4 // 与原生的Promise.all返回是一致的

额外题目

使用Promise.all进行5个请求,若其中一个失败,如何返回其他4个成功???

Promise.MyAll = function(promise){
   let arr = []
   count = 0 
   return new Promise((resolve,reject)=>{
      promise.forEach((item,i)=>{
        Promise.resolve(item).then(res=>{
          arr[i] = res
        }).catch((err)=>{
          arr[i]= false
        }).finally(()=>{
          count ++ ;
          if(count === promise.length)resolve(arr)
        })
      })
   })
}

Promise.race()

Promise.MyRace = function(promise){
   return new Promise((resolve,reject)=>{
     for(const item of promise){
        Promise.resolve(item).then(resolve,reject)
     }
   })
}