手写Promise

162 阅读2分钟

前言

手写自然不会要求写全, 只要实现基本的常用的几个api。我们要实现的几个功能如下

new Promise((resolve, reject)=>{

})
.then()
.catch()
Promise.resolve()
Promise.reject()
Promise.all()
Promise.race()

构造函数

  • promise 有三个状态
  • 状态一旦修改不可逆转 请根据以上两点查看下面代码
class MyPromise{
  status = 'pending' // resolved rejected
  value = undefined
  reason = undefined
  constructor(fn) {
    const resolveHandler = (v) => {
      if(this.status === 'pending') {
        this.status = 'resolved'
        this.value = v
      }
    }
    const rejectHandler = (e) => {
      if(this.status === 'pending') {
        this.status = 'rejected'
        this.reason = e
      }
    }
    try {
      fn(resolveHandler, rejectHandler)
    } catch (error) {
      rejectHandler(error)
    }
  }
}

then

  • then 有两个入参, 第一个是resolve调用, 第二个是reject调用
  • then会返回一个新的promise

请根据以上两条参考来查看以下代码

  • 情况一: 传入的函数直接调用resolve
// 测试示例
new MyPromise((resolve, reject)=>{
  resolve(100)
}).then(val=>{
    console.log(val)
    return 200
}).then(val=>{
    console.log(val)
})

// 主体部分
then(successFn, errorFn){
    successFn = typeof successFn === 'function' ? successFn : v=>v
    errorFn = typeof errorFn === 'function' ? errorFn : e=> {throw e}

    if(this.status === 'resolved'){
      return new MyPromise((resolve, reject)=>{
        try {
          const val = successFn(this.value)
          resolve(val)
        } catch (error) {
          reject(error)
        }
      })
    }
}
  • 情况二: 传入的函数直接调用reject, 实现和上面的基本一致
// 测试示例
new MyPromise((resolve, reject)=>{
  reject(new Error('错误1'))
}).then(null, err=>{
    console.log(err.message)
})
new MyPromise((resolve, reject)=>{
    throw new Error('错误2')
  resolve()
}).then(null, err=>{
    console.log(err.message)
    throw new Error('错误3')
}).then(null, err=>{
    console.log(err.message)
    return 200
}).then(val=>{console.log(val)})

// 主体部分

then(successFn, errorFn){
    successFn = typeof successFn === 'function' ? successFn : v=>v
    errorFn = typeof errorFn === 'function' ? errorFn : e=> {throw e}

    if(this.status === 'rejected'){
      return new MyPromise((resolve, reject)=>{
        try {
          const val = errorFn(this.reason)
          resolve(val)
        } catch (error) {
          reject(error)
        }
      })
    }
}
  • 情况三: 传入的函数异步调用resolve 或 reject
  • 执行then时, 还不知道成功还是失败, 所以放回的Promise也不能直接调用 resolve或reject
  • 需要等待之前的promise返回结果再进行调用
// 测试示例
new MyPromise((resolve, reject)=>{
  setTimeout(() => {
    resolve(100)
  }, 1000);
}).then(val=>{
    console.log(val)
})

class MyPromise{
      resolveCallbacks = []
      rejectCallbacks = []
      constructor(fn) {
        const resolveHandler = (v) => {
          if(this.status === 'pending') {
            this.status = 'resolved'
            this.value = v
            this.resolveCallbacks.forEach(fn=>fn())
          }
        }
        const rejectHandler = (e) => {
          if(this.status === 'pending') {
            this.status = 'rejected'
            this.reason = e
            this.rejectCallbacks.forEach(fn=>fn())
          }
        }
      }
      then(successFn, errorFn){
        if(this.status === 'pending'){
          return new MyPromise((resolve, reject)=>{
            this.resolveCallbacks.push(()=>{
              try {
                const val = successFn(this.value)
                resolve(val)
              } catch (error) {
                reject(error)
              }
            })
            this.rejectCallbacks.push(()=>{
              try {
                const val = errorFn(this.reason)
                resolve(val)
              } catch (error) {
                reject(error)
              }
            })
          })
        }
      }
    }

catch/Promise.resolve()/Promise.reject()

这个就很简单了, then中其实已经实现了catch的功能了

catch(errorFn){
    return this.then(null, errorFn)
  }

Promise.resolve

MyPromise.resolve = (val)=>{
  return new MyPromise((resolve)=>{
    resolve(val)
  })
}

Promise.reject

MyPromise.reject = (err)=>{
  return new MyPromise((resolve, reject)=>{
    reject(err)
  })
}

Promise.all

MyPromise.all = (promiseList = [])=>{
  return new MyPromise((resolve, reject)=>{
    const resList = []
    let resIndex = 0
    promiseList.forEach(p=>{
      p.then(res=>{
        resList.push(res)
        resIndex++
        if(resIndex === promiseList.length){
          resolve(resList)
        }
      }).catch(err=>{
        reject(err)
      })
    })
  })
}

Promise.race

MyPromise.race = (promiseList = [])=>{
  return new MyPromise((resolve, reject)=>{
    promiseList.forEach(p=>{
      p.then(res=>{
        resolve(res)
      }).catch(err=>{
        reject(err)
      })
    })
  })
}