面试常问- Promise.all race any...实现源码

213 阅读3分钟

前言

最近在准备暑假实习,因为看着Promise的方法经常会被问到,以及源码怎么写,特此来总结一波,希望可以帮到大家!!Talk is Cheap,Take me Code. 咱们少说废话,直接上代码。

Promise方法介绍和代码

下面方法的介绍及测试均使用这五个Promise实例

const p1 = Promise.resolve('p1')
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p2 延时一秒')
  }, 1000)
})
const p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('p3 延时两秒')
  }, 2000)
})

const p4 = Promise.reject('p4 rejected')

const p5 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('p5 rejected 延时1.5秒')
  }, 1500)
})

Promise.all

简单介绍

  • Promise.all接收一个可遍历的数据容器,容器中每个元素都应是 Promise实例。咱就是说,假设这个容器就是数组。

  • 数组中每个 Promise 实例都成功时(pendding=>fulfilled),Promise.all 才成功。这些 Promise 实例所有的 resolve 结果会按照原来的顺序集合在一个数组中作为 Promise.all 的 resolve 的结果。

  • 数组中只要有一个 Promise 实例失败(pendding=>rejected),Promise.all 就失败。Promise.all 的 .catch()会捕获到这个 reject.

代码

Promise.myAll = function(promises){
  let arr =[],count =0;
  return new Promise((resolve,reject)=>{
    promises.forEach((item,i)=>{
      Promise.resolve(item).then(res=>{
        arr[i] = res;
        count +=1;
        if(count === promises.length) {
          resolve(arr)
        }
      }).catch(reject)
    })
  })
}

结果

// 所有 Promsie 都成功
Promise.myAll([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 2秒后打印 [ 'p1', 'p2 延时一秒', 'p3 延时两秒' ]
  
// 一个 Promise 失败
Promise.myAll([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p4 rejected
  
// 一个延时失败的 Promise
Promise.myAll([p1, p2, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 1.5秒后打印 p5 rejected 延时1.5秒
 
// 两个失败的 Promise
Promise.myAll([p1, p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p4 rejected

Promise.race

简单介绍

Promise.race 从字面意思理解就是赛跑,以状态变化最快的那个 Promise 实例为准,最快的 Promise 成功 Promise.race 就成功,最快的 Promise 失败 Promise.race 就失败。

代码

Promise.myRace = function (promises) {
    return new Promise((resolve, reject) => {
      // 这里不需要使用索引,只要能循环出每一项就行
      for (const item of promises) {
        Promise.resolve(item).then(resolve, reject)
        console.log(item);
      }
    })
  }

结果

// p1无延时,p2延时1s,p3延时2s
Promise.myRace([p2, p1, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1

// p4无延时reject
Promise.myRace([p4, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p4 rejected
  
// p5 延时1.5秒reject,p2延时1s
Promise.myRace([p5, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // 1s后打印: p2 延时一秒

Promise.any

简单介绍

只要其中的一个 promise 成功,就返回那个已经成功的 promise。如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和 AggregateError 类型的实例,它是 Error 的一个子类,用于把单一的错误集合在一起。

代码

Promise.myAny = function(promises){
  let arr=[],count=0;
  return new Promise((resolve,reject)=>{
    promises.forEach((item,i)=>{
      Promise.resolve(item).then(resolve).catch(err=>{
        arr[i] = {status:'rejected',val:err}
        count+=1;
        if(count === promises.length){
          reject(new Error('All promises were rejected'))
        }
      })
    })
  })
}

结果

//所有 Promise 都成功
Promise.myAny([p1, p2, p3])
  .then(res => console.log(res)) //p1
  .catch(err => console.log(err)) 
  
//两个 Promise 成功
Promise.myAny([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p1

//只有一个延时成功的 Promise
Promise.myAny([p2, p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // p2 延时1秒

// 所有 Promise 都失败
Promise.myAny([p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err)) // All promises were rejected

Promise.allSettled

简单介绍

如果希望一组 Promise 实例无论成功与否,都等它们异步操作结束了在继续执行下一步操作

代码

Promise.myAllSettled = function(promises){
  let arr = [],count =0
  return new Promise((resolve,reject)=>{
    promises.forEach((item,i)=>{
      Promise.resolve(item).then(res=>{
        arr[i] = {status:'fulfilled',value:res}
        count += 1 
        if(count === promises.length) return resolve(arr)
      },err=>{
        arr[i] = {status:'rejected',reason:err}
        count += 1 
        if(count === promises.length) return resolve(arr)
      })
    })
  })
}

结果

// 所有 Promise 实例都成功
Promise.myAllSettled([p1, p2, p3])
  .then(res => console.log(res))
  .catch(err => console.log(err))
//  [ 0: {status: 'fulfilled', value: 'p1'}
//   1: {status: 'fulfilled', value: 'p2 延时一秒'}
//   2: {status: 'rejected', reason: 'p4 rejected'}
//  ] 
//有一个Promise失败
Promise.myAllSettled([p1, p2, p4])
  .then(res => console.log(res))
  .catch(err => console.log(err))
//   [
//    0: {status: 'fulfilled', value: 'p1'}
//    1: {status: 'fulfilled', value: 'p2 延时一秒'}
//    2: {status: 'fulfilled', value: 'p3 延时两秒'}
//   ]

//所有的Promise都失败
Promise.myAllSettled([p4, p5])
  .then(res => console.log(res))
  .catch(err => console.log(err))
//   [
//    0: {status: 'rejected', reason: 'p4 rejected'}
//    1: {status: 'rejected', reason: 'p5 rejected 延时1.5秒'}
//   ]

结语

本人太菜,写的只是自己的一点点见解,如有问题还望大佬不吝啬的指出来。