理解和手写Promise.all和Promise.race

·  阅读 1328

Promise.all和Promise.race的介绍

  • 相似点:
    • 这两个都是Promise的方法,并且传入的参数都是一个Promise的数组。
    • 都会返回一个Promise实例
  • 区别:
    • all: 传入的所有Promise最终都转化为fulfilled态时,则会执行resolve回调,并将返回值是的所有的Promiseresolve的回调的value的数组。其中一个任何Promisereject状态时,则返回的Promise的状态更改为rejected
    • race: 传入的所有Promise其中任何一个有状态转化为fulfilled或者rejected,则将执行对应的回调。

如果觉得表述模糊不清,请点击MDN的Promise介绍页面

示例代码

promise.all。以下代码涵盖all中Promise可能出现的各种状态

//p1:0.5s后转化为fullfilled状态
let p1 = new Promise((res,rej) => {
  setTimeout(()=>{
    res("p1调用成功")
  },500)
})

//p2: 直接转化为res状态
let p2 = new Promise((res,rej) => {
  res("p2调用成功")
})

//p3: 1s后转化为rejected状态
let p3 = new Promise((res,rej) => {
  setTimeout(()=>{
    rej("p3失败了...")
  },1000)
})

//p4: 2s后转化为rejected状态
let p4 = new Promise((res,rej) => {
  setTimeout(()=>{
    rej("p4失败了...")
  },2000)
})
// 传入p1,p2
Promise.all([p1,p2]).then(res =>{
  console.log(res); // ['p1调用成功','p2调用成功']
}).catch(rej => {
  console.log(rej);
})

//传入p3
Promise.all([p1,p2,p3]).then((res,rej) => {
  console.log(res);
}).catch(rej => {
  console.log(rej);  //p3失败了...
})

//传入p4
Promise.all([p1,p2,p3,p4]).then((res,rej) => {
  console.log(res);
}).catch(rej => {
  console.log(rej);  //p3失败了...
})

复制代码

promise.race。以下代码涵盖race中Promise可能出现的各种状态

//p1:0.5s后转化为fullfilled状态
let p1 = new Promise((res,rej) => {
  setTimeout(()=>{
    res("p1调用成功")
  },500)
})

//p2: 直接转化为res状态
let p2 = new Promise((res,rej) => {
  res("p2调用成功")
})

//p3: 1s后转化为rejected状态
let p3 = new Promise((res,rej) => {
  setTimeout(()=>{
    rej("p3失败了...")
  },1000)
})

//p4: 2s后转化为rejected状态
let p4 = new Promise((res,rej) => {
  setTimeout(()=>{
    rej("p4失败了...")
  },2000)
})

//传入p1,p2
Promise.race([p1,p2]).then(res =>{
  console.log(res)  //p2调用成功
})

//传入p1,p3
Promise.race([p1,p3]).then(res => {
  console.log(res)  //p1调用成功
}).catch(rej => {
  console.log(rej)  
})

//传入p3,p4
Promise.race([p3,p4]).then(res => {
  console.log(res) 
}).catch(rej => {
  console.log(rej)  //p3失败了...
})
复制代码

面试考点

看到这里相信你应该对这两个方法有一定的理解,面试会问那些相关的问题呢?

使用场景

当用户想要得到的是多个异步结果合并到一起时应该使用all 当我们想要控制某一个异步操作的时间时,就可以用定时器和race来进行实现。

传入空数组

当我们的allrace传入的是空数组时,会有出现什么状况呢?

  • all: 感谢楼下评论的提醒,后来去看了MDN上promise.all的讲解,发现是返回一个状态是resovle的promise对象。
  • race: 返回的Promise会一直保持在pending状态。

手写实现

Promise.all
function all(arr){
  //返回一个promise
  return new Promise((res,rej) => {
    let length = arr.length  //传入的promise的个数
    let count = 0  //进入fullfilled的promise个数
    const result = []  //创建一个等长的数组,放置结果
    // 当传递是一个空数组,返回一个为fulfilled状态的promise
    if(arr.length === 0 ) {
      return new Promise.resolve(arr)
    }
    for(let i = 0; i < arr.length; i++){
      arr[i].then(resolve => {
        result.push(resolve) //将每次结果保存在result数组中
        count ++  //个数加1
        //是否所有的promise都进入fullfilled状态
        if(count === length){
          res(result)  //返回结果
        }
      }).catch(e => {
        rej(e)  //如果有错误则直接结束循环,并返回错误
      })
    }
  })
}
复制代码
Promise.race
function race(arr){
  return new Promise((res,rej) => {
    for(let i = 0; i < arr.length; i++){
      arr[i].then(resolve => {
        res(resolve)  //某一promise完成后直接返回其值
      }).catch(e => {
        rej(e)  //如果有错误则直接结束循环,并返回错误
      })
    }
  })
}
复制代码
分类:
前端
标签:
分类:
前端
标签: