一个用于面试的Promise源码

下面是一个用于面试的简单版的Promise

function MyPromise(executor){
  if(typeof executor !== 'function') throw new Error('请传入执行器函数executor 例如function(resolve,reject){}')//必须传入executor函数,如果不传是会报错的
  let self = this;//保存this
  self.status = 'pending';//promise总共有三种状态,pending、fulfilled、reject,一旦状态改变就不可逆转,(很多面试管都喜欢问你当pending变为fulfilled之后还能变成reject?)
  self.value = null;//用于保存结果值
  self.onResolveCallBack = [];//当resolve在异步中执行的时候,用于保存then中要执行的函数,让resolve的时候在遍历执行里面的函数
  self.onRejectCallBack = [];//reject同上(resolve)

  function resolve(value){//resolve函数
    if(self.status === 'pending'){
      self.status = 'fulfilled'//进来之后就改变stauts的状态,这就是为什么status状态是不可逆的,(self.status === 'pending')
      self.value = value
      self.onResolveCallBack.forEach(fn => fn())//用于异步resolve执行then中的回调
    }
  }
  function reject(value) {//同上(resolve)
    if(self.status === 'pending'){
      self.status = 'reject';
      self.value = value;
      self.onRejectCallBack.forEach(fn => fn())
    }
  } 
  try {
    executor(resolve,reject)//promise的执行器,放在try中防止出错
    
  } catch (error) {
    throw new Error(error)
  }

}
MyPromise.prototype.then = function (fn1,fn2) {//fn1是成功的时候执行的,fn2是失败的时候执行和catch捕获的是一样的
  let self = this;
  // 根据规范,如果then的参数不是function,则我们需要忽略它, 让链式调用继续往下执行
  typeof fn1 === 'function' ? null : fn1 = (value) => value;
  typeof fn2 === 'function' ? null : fn2 = (reason) =>{
    throw new Error(reason instanceof Error ? reason.message : reason)
  }
  return new MyPromise((resolve,reject)=> {//promise可以链式调用就是因为then中重新返回一个promise
    if(self.status === 'fulfilled'){//当成功的时候执行fn1
      try {
        let result = fn1(self.value)
        resolve(result) //用于下个then
      } catch (error) {
        reject(error)
      }
     
    }
    if(self.status === 'reject'){//当失败的时候执行
      try {
        if(typeof fn2 === 'function'){//如果then中没有传第二个函数就把value值直接放入reject用于后面的catch捕获
          let result = fn2(self.value);
          reject(result)
        }else{
          reject(self.value)
        }
      } catch (error) {
        reject(error)
      }
      
    }
    //如果是pending说明执行器executor中的resolve() 在异步中执行的,我们
    //就把then中的回调函数放入onResolveCallBack当执行resolve()的时候拿到value值之后,在去遍历
    if(self.status === 'pending'){
      self.onResolveCallBack.push(()=>{
        let result = fn1(self.value);
        resolve(result)
      })
      self.onRejectCallBack.push(()=>{
        let result = fn2(self.value);
        resolve(result)
      })
    }
  })
}
MyPromise.prototype.catch = function(errFn) {//类似于then,只要处理错误回调就行了
  return this.then(undefined, errFn)
}
MyPromise.isPromise = function(value) {//简单判断是否是个Promise函数
 return typeof value.then === 'function'
}
MyPromise.all = function(value) {//简单实现promise中all方法
  let self =this;
  if(!Array.isArray(value)){
    throw new Error('value is not array')
  }
  if(value.length === 0){
    return []
  }
  return new MyPromise(function(resolve,reject){//all方法返回的是个promise
    let result = [];
    let count = 0;//用于计数,当value的长度和count相等就resolve,也是all方法比较核心的地方
    for(let i = 0; i<value.length; i++){
      let currentV = value[i]
      let isPromise = MyPromise.isPromise(currentV);
      if(isPromise){
        currentV.then(res =>{
          count++
          result[i] = res;
          if(count === value.length)return resolve(result)
        },err=>{
          reject(err,9999)
        }).catch(err=> {
          reject(err)
        })
      } else{
        count++
        result[i] = currentV;
        if(count === value.length)return resolve(result)
      }
    }

  })
}
MyPromise.reac = function (value) {
  if(!Array.isArray(value)){throw new Error('请传入一个array')}
  return new MyPromise((resolve,reject)=>{
    for(let i = 0; i<value.length; i++){
      let currentV = value[i];
      if(MyPromise.isPromise(currentV)){
        currentV.then(res =>{
          resolve(res)
        })

      }else {
        resolve(currentV)
      }
    }
  })
}
MyPromise.resolve = function(value) {
  return new MyPromise((resolve,reject) => {
    resolve(value)
  })
}
MyPromise.reject = function(value) {
  return new MyPromise((resolve,reject)=> {
    reject(value)
  })

}



// let test = new MyPromise(function(resolve,reject){
//   setTimeout(() => {
//    resolve(222)
//   }, 2000);
// })
// test.then(res=>{
//   console.log(res)
// })

// let isPromise = MyPromise.isPromise(new MyPromise(function(){}));
// console.log(isPromise,'isPromise')
// let myP = new MyPromise(() =>{})
// console.log(myP)
let p1 = new MyPromise((resolve,reject)=>{ reject(1)})
let p2 = new MyPromise((resolve,reject)=>{ resolve(2)})
let p3 = new MyPromise((resolve,reject)=>{ resolve(3)})
let p4 = new MyPromise((resolve,reject)=>{ resolve(4)})
let p5 = new MyPromise((resolve,reject)=>{ resolve(5)})

MyPromise.all([p1,p2,p3,p4,p5,99]).then(res =>{
  console.log(res)
}).catch(err =>{
  console.log(err,999)
})

// MyPromise.reac([34234,p1]).then((res) =>{
//   console.log(res,'reac')
// })
// MyPromise.resolve(4444555).then(res=> {
//   console.log(res,'resolve')
//   return 'test'
// }).then(res =>{
//   console.log(res,'8866')
// })
// console.log(MyPromise.prototype.constructor.name,'78whidfgdgkjdh')
let myP = new MyPromise(function(resolve,reject){
      // reject(1)
  setTimeout(() => {
    reject(1)
  }, 1000);
})
myP.then(res=> {
  console.log(res,8888)
}).catch((err)=>{
  console.log(err,'console.error();')
})

clas类写法

//Promise/A+规定的三种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  // 构造方法接收一个回调
  constructor(executor) {
    this._status = PENDING     // Promise状态
    this._value = undefined    // 储存then回调return的值
    this._resolveQueue = []    // 成功队列, resolve时触发
    this._rejectQueue = []     // 失败队列, reject时触发

    // 由于resolve/reject是在executor内部被调用, 因此需要使用箭头函数固定this指向, 否则找不到this._resolveQueue
    let _resolve = (val) => {
      //把resolve执行回调的操作封装成一个函数,放进setTimeout里,以兼容executor是同步代码的情况
      const run = () => {
        if(this._status !== PENDING) return   // 对应规范中的"状态只能由pending到fulfilled或rejected"
        this._status = FULFILLED              // 变更状态
        this._value = val                     // 储存当前value

        // 这里之所以使用一个队列来储存回调,是为了实现规范要求的 "then 方法可以被同一个 promise 调用多次"
        // 如果使用一个变量而非队列来储存回调,那么即使多次p1.then()也只会执行一次回调
        while(this._resolveQueue.length) {    
          const callback = this._resolveQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }
    // 实现同resolve
    let _reject = (val) => {
      const run = () => {
        if(this._status !== PENDING) return   // 对应规范中的"状态只能由pending到fulfilled或rejected"
        this._status = REJECTED               // 变更状态
        this._value = val                     // 储存当前value
        while(this._rejectQueue.length) {
          const callback = this._rejectQueue.shift()
          callback(val)
        }
      }
      setTimeout(run)
    }
    // new Promise()时立即执行executor,并传入resolve和reject
    executor(_resolve, _reject)
  }

  // then方法,接收一个成功的回调和一个失败的回调
  then(resolveFn, rejectFn) {
    // 根据规范,如果then的参数不是function,则我们需要忽略它, 让链式调用继续往下执行
    typeof resolveFn !== 'function' ? resolveFn = value => value : null
    typeof rejectFn !== 'function' ? rejectFn = reason => {
      throw new Error(reason instanceof Error? reason.message:reason);
    } : null
  
    // return一个新的promise
    return new MyPromise((resolve, reject) => {
      // 把resolveFn重新包装一下,再push进resolve执行队列,这是为了能够获取回调的返回值进行分类讨论
      const fulfilledFn = value => {
        try {
          // 执行第一个(当前的)Promise的成功回调,并获取返回值
          let x = resolveFn(value)
          // 分类讨论返回值,如果是Promise,那么等待Promise状态变更,否则直接resolve
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (error) {
          reject(error)
        }
      }
  
      // reject同理
      const rejectedFn  = error => {
        try {
          let x = rejectFn(error)
          x instanceof MyPromise ? x.then(resolve, reject) : resolve(x)
        } catch (error) {
          reject(error)
        }
      }
  
      switch (this._status) {
        // 当状态为pending时,把then回调push进resolve/reject执行队列,等待执行
        case PENDING:
          this._resolveQueue.push(fulfilledFn)
          this._rejectQueue.push(rejectedFn)
          break;
        // 当状态已经变为resolve/reject时,直接执行then回调
        case FULFILLED:
          fulfilledFn(this._value)    // this._value是上一个then回调return的值(见完整版代码)
          break;
        case REJECTED:
          rejectedFn(this._value)
          break;
      }
    })
  }
  catch(rejectFn) {
    return this.then(undefined, rejectFn)
  }
}
let result = new MyPromise((resolve,reject)=>{
  setTimeout(() => {
    reject(1000)
  }, 1000);
})
result.then(res=>{
  console.log('success',res)
}).catch(err=>{
  console.log(err,'console.error();')
})

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值