手撸 Promise (then、catch)

606 阅读2分钟

最近也处于校招面试当中,当然也少不了对 Promise 的话题了。打开 MDN,对着 Promise 的方法,把 then 和 catch 撸了出来。

developer.mozilla.org/zh-CN/docs/… 这是 MDN 中对 Promise 的详细介绍。

属性

function myPromise(executor) {
  const self = this

  self.status = 'pending'
  self.value = undefined

  self.onResolvedCallbacks = []
  self.onRejectedCallbacks = []

  function resolve(value) {
    if (self.status === 'pending') {
      self.status = 'fulfilled'
      self.value = value
      self.onResolvedCallbacks.forEach(fn => fn(self.value))
    }
  }

  function reject(error) {
    if (self.status === 'pending') {
      self.status = 'rejected'
      self.value = error
      self.onResolvedCallbacks.forEach(fn => fn(self.value))
    }
  }

  try {
    executor(resolve, reject)
  } catch (error) {
    reject(error)
  }
}

我们看到 MDN 中对 executor 的介绍:

executor 是带有 resolve 和 reject 两个参数的函数,Promise构造函数执行时立即调用executor 函数。

resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)

executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。

then

myPromise.prototype.then = function (onFulfilled, onRejected) {
  // then 传入的参数不是 function,要忽略它
  onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
  onRejected = typeof onRejected === 'function' ? onRejected : reason => {
    throw reason
  }

  const self = this

  if (self.status === 'fulfilled') {
    return new myPromise((resolve, reject) => {
      try {
        let x = onFulfilled(self.value)
        if (x instanceof myPromise) {
          x.then(resolve, reject)
        }
        resolve(x)
      } catch (e) {
        reject(e)
      }      
    })
  }

  if (self.status === 'rejected') {
    return new myPromise((resolve, reject) => {
      try {
        let x = onRejected(self.value)
        if (x instanceof myPromise) {
          x.then(resolve, reject)
        }
        resolve(x)
      } catch (e) {
        reject(e)
      }
    })
  }

  // 异步
  if (self.status === 'pending') {
    return new myPromise((resolve, reject) => {
      self.onResolvedCallbacks.push((value) => {
        try {
          let x = onFulfilled(value)
          if (x instanceof myPromise) {
            x.then(resolve, reject)
          }
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
       
      self.onRejectedCallbacks.push((value) => {
        try {
          let x = onRejected(value)
	  if (x instanceof myPromise) {
            x.then(resolve, reject)
          }
	  resolve(x)
        } catch (e) {
	  reject(e)
        }
      })
    })
  }
}

MDN 中 then 的解释:

添加解决(fulfillment)和拒绝(rejection)回调到当前 promise, 返回一个新的 promise, 将以回调的返回值来resolve.

catch

myPromise.prototype.catch = function (onRejected) {
  // then 传入的参数不是 function,要忽略它
  onRejected = typeof onRejected === 'function' ? onRejected : reason => {
    throw reason
  }

  const self = this

  if (self.status === 'fulfilled') {
    return new myPromise((resolve, reject) => {
      try {
        resolve(self.value)
      } catch (e) {
        reject(e)
      }
    })
  }

  if (self.status === 'rejected') {
    return new myPromise((resolve, reject) => {
      try {
        let x = onRejected(self.value)
        if (x instanceof myPromise) {
          x.then(resolve, reject)
        }
	resolve(x)
      } catch (e) {
        reject(e)
      }
    })
  }

  // 异步
  if (self.status === 'pending') {
    return new myPromise((resolve, reject) => {
      self.onRejectedCallbacks.push((value) => {
        try {
          let x = onRejected(value)
          if (x instanceof myPromise) {
            x.then(resolve, reject)
          }
          resolve(x)
        } catch (e) {
          reject(e)
        }
      })
    })
  }
}

MDN 中 catch 的解释:

添加一个拒绝(rejection) 回调到当前 promise, 返回一个新的promise。当这个回调函数被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当前promise的完成结果作为新promise的完成结果.