面试官问:怎么实现Promise.all

150 阅读4分钟

现在出去面试,不会点promise原理promise的方法,人家就会觉得你基础知识不扎实,或者是没有亮点,反正就是看不上你,今天我们就来聊一聊promise的各个方法如何实现吧。

Promise.resolve

规范

  • Promise.resolve返回一个Promise
  • 传入的参数如果是一个Promise,则直接返回
  • 传入的参数如果不是一个Promise,则需要new Promise包装一下 小栗子
   //非promise对象,非thenable对象
    const obj=Promise.resolve('1')
    obj.then((response,reject)=>{
      console.log(response,reject);

    })
    console.log(obj);

    //promise成功对象
    const p=new Promise(resolve=>resolve('2'))
    const obj2=Promise.resolve(p).then(res=>console.log(res))
    console.log(obj2);

    //promise 失败对象
    const p2=new Promise((resolve,reject)=>reject('error3'))
    const obj3=Promise.resolve(p2).catch(res=>console.log(res))
    console.log(obj3)

源码实现

 Promise.myResolve=value=>{
      //如果是promise对象,则直接返回
      if(value&& typeof value ==='object'&& (value instanceof Promise)){
        return value
      }
      //否则用promise再包装一下
      return new Promise(resolve=>{
        resolve(value)
      })
    }

Promise.all

规范

Promise.all()方法用于将多个Promise实例,包装成一个Promise实例。常用于async/await中,多个await之间没有依赖关系,减少性能消耗。

const p1=Promise.all([p1,p2,p3])

最终p的状态由p1、p2、p3决定,分为2种情况:

  • p1、p2、p3的状态都为fullfilled时,p的状态就为fullfilled,此时p1、p2、p3的返回值组成一个数组,返回给p的回调
  • p1、p2、p3的状态有一个为rejected时,那么p的状态就为rejected,此时第一个被reject实例的返回值,会返回给p的回调
  • 如果其中某个实例不是Promise对象,则Promise.all会将它转为Promise对象 小栗子
      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')
      const p11=Promise.all(['23',p2,p3]).then(res=>{
        console.log(res);
      }).catch(err=>console.log(err))

      const p12=Promise.all([p1,p2,p4]).then(res=>{
        console.log(res);
      }).catch(err=>console.log(err))

      const p13=Promise.all([p1,p5,p4]).then(res=>{
        console.log(res);
      }).catch(err=>console.log(err))

源码实现

Promise.myAll=(promises)=>{   
    return new Promise((resolve,reject)=>{
      let len=promises.length
      let result=[]
      if(!len){
        resolve([])
      }
      promises.forEach((promise,index)=>{
        //有的数组项不是promise对象,需要转化一下
        Promise.resolve(promise).then((res)=>{
          //将结果存入数组中
          result[index]=res
          //当所有promise都执行完且成功时,那么将返回的promise结果设置为result
          if(index===len-1){
            resolve(result)
          }
          //监听数组项中的每一项, catch 只有有一个失败,那么我们返回的promise也失败了
        }).catch(err=>reject(err))

      })
    })
    }
    
  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')
  const p11=Promise.myAll(['23',p2,p3]).then(res=>{
    console.log(res);
  }).catch(err=>console.log(err))

  const p12=Promise.myAll([p1,p2,p4]).then(res=>{
    console.log(res);
  }).catch(err=>console.log(err))

  const p13=Promise.myAll([p1,p5,p4]).then(res=>{
    console.log(res);
  }).catch(err=>console.log(err))
  const p14=Promise.myAll([]).then(res=>{
    console.log(res);
  })

Promise.race

规范

只要p1、p2、p3实例之中有一个状态率先改变,那么p的状态就跟着改变。 应用场景

  • 后端代码部署在多台服务器上,前端race中写各个服务器连接方法,谁响应快就用谁的。
  • 前端代码发起请求或异步回调时,在规定时间内未请求成功就直接走失败方法。 小栗子
const p1=Promise.resolve('1')
const p2=new Promise(resolve=>{
  setTimeout(() => {
    resolve('2')
  }, 1000);
})
const p3=new Promise(resolve=>{
  setTimeout(() => {
    resolve('3')
  }, 2000);
})
const p4=Promise.reject('err4')
const p11=Promise.race([p1,p2]).then(res=>{
  console.log(res);  //1
})
const p14=Promise.race(['33',p1]).then(res=>{
  console.log(res);  //33
})
const p12=Promise.race([p3,p2]).then(res=>{
  console.log(res);  //2
})
const p13=Promise.race([p2,p4]).then(res=>{
  console.log(res);
}).catch(err=>console.log(err))  // err4

源码实现

Promise.myRace=(promises)=>{
  return new Promise((resolve,reject)=>{
    promises.forEach(promise=>{
      Promise.resolve(promise).then(res=>resolve(res)).catch(err=>reject(err))
    })
  })
}
const p1=Promise.resolve('1')
const p2=new Promise(resolve=>{
  setTimeout(() => {
    resolve('2')
  }, 1000);
})
const p3=new Promise(resolve=>{
  setTimeout(() => {
    resolve('3')
  }, 2000);
})
const p4=Promise.reject('err4')
const p11=Promise.myRace([p1,p2]).then(res=>{
  console.log(res);  //1
})
const p14=Promise.myRace(['33',p1]).then(res=>{
  console.log(res);  //33
})
const p12=Promise.myRace([p3,p2]).then(res=>{
  console.log(res);  //2
})
const p13=Promise.myRace([p2,p4]).then(res=>{
  console.log(res);
}).catch(err=>console.log(err))  // err4

Promise.allSettled

规范

有时候我们想要在一组promise全部执行完,在继续下面的操作,不管每一个实例的结果是fullfilled还是rejected,都等他全部执行完,再执行后面的代码。Promise.all是只要有一个reject,就会中断执行,不符合我们的需求。

小栗子

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.allSettled([ p1, p2, p3 ])
	.then((res) => console.log(JSON.stringify(res, null,  2)))

// 输出 
/*
[
  {
    "status": "fulfilled",
    "value": 1
  },
  {
    "status": "fulfilled",
    "value": 2
  },
  {
    "status": "fulfilled",
    "value": 3
  }
]
*/
      
// 2. 有一个Promise失败了
const p12 = Promise.allSettled([ p1, p2, p4 ])
	.then((res) => console.log(JSON.stringify(res, null,  2)))
        
// 输出 
/*
[
  {
    "status": "fulfilled",
    "value": 1
  },
  {
    "status": "fulfilled",
    "value": 2
  },
  {
    "status": "rejected",
    "reason": "err4"
  }
]
*/
      
// 3. 有两个Promise失败了
const p13 = Promise.allSettled([ p1, p4, p5 ])
	.then((res) => console.log(JSON.stringify(res, null,  2)))
        
// 输出 
/*
[
  {
    "status": "fulfilled",
    "value": 1
  },
  {
    "status": "rejected",
    "reason": "err4"
  },
  {
    "status": "rejected",
    "reason": "err5"
  }
]
*/

源码实现

Promise.myAllSettled=(promises)=>{
  return new Promise((resolve,reject)=>{
    let result=[]
    let len=promises.length
    if(!len){
      resolve([])
    }
    promises.forEach((promise,index)=>{
      Promise.resolve(promise).then(res=>{
        result[index]={
          statu:'fulfilled',
          value:res
        }
        if(index===len-1){
          resolve(result)
        }
      }).catch(err=>{
        result[index]={
          statu:'rejected',
          value:err
        }
         if(index===len-1){
          resolve(result)
        }


      })
    })
  })

}

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.myAllSettled([ p1, p2, p3 ])
  .then((res) => console.log(JSON.stringify(res, null,  2)))
const p12 = Promise.myAllSettled([ p1, p2, p4 ])
      .then((res) => console.log(JSON.stringify(res, null,  2)))
const p13 = Promise.myAllSettled([ p1, p4, p5 ])
      .then((res) => console.log(JSON.stringify(res, null,  2)))

结尾

如有错误,欢迎大家指正啦