实现 Promise

197 阅读1分钟

相关概念看这篇规范的翻译 malcolmyu.github.io/2015/06/12/…

代码参考 imweb.io/topic/5bbc2…

直接上代码

function Promise(fn) {
  let self = this
  this.status = 'pending' // Promise 初始状态为 pending
  this.value = undefined // Promise 的值
  this.onFulfilledCallbacks = [] // resolve 回调函数集合
  this.onRejectedCallbacks = [] // reject 回调函数集合
  
  // 定义 resolve
  function resolve(value) {
    self.status = 'resolved'
    self.value = value
    // 回调并不是立即执行的
    // 所有使用 setTimeout
    setTimeout(function () {
      for (let i = 0; i < self.onFulfilledCallbacks.length; i++) {
        self.onFulfilledCallbacks[i](value)
      }
    })
  }
  
  // 定义 reject
  function reject(reason) {
    if (self.status === 'pending') {
      self.status = 'rejected'
      self.value = reason
      // 回调并不是立即执行的
      // 所有使用 setTimeout
      setTimeout(function () {
        for (let i = 0; i < self.onRejectedCallbacks.length; i++) {
          self.onRejectedCallbacks[i](reason)
        }
      })
    }
  }
  
  try {
    // 执行传进来的函数,传入 resolve, reject 参数
    fn(resolve, reject) 
  } catch (error) {
    reject(error)
  }
}

// then 方法
Promise.prototype.then = function (onFulfilled, onRejected) {
  // 根据标准,如果 then 的参数不是 function,则我们需要忽略它(给一个默认函数)
  onFulfilled = 
    typeof onFulfilled === 'function' 
      ? onFulfilled 
      : noop
  
  onRejected = 
    typeof onRejected === 'function' 
      ? onRejected 
      : noop
    
  if (self.status === 'resolved') {
    // 这里 promise 的状态已经确定是 resolved,所以调用 onResolved
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        try {
          // res 是 onFulfilled 的返回值
          var res = onFulfilled(self.data)
          if (res instanceof Promise) {
            // 如果 res 是一个 promise,则取其值作为新的 promise 的结果
            res.then(resolve, reject)
          } else {
            // 否则,以它的返回值作为新的promise的结果
            resolve(res)
          }
        } catch (error) {
          // 如果出错,则捕获
          reject(error)
        }
      })
    })
  }
  
  // reject 逻辑和 resolve 类似
  if (self.status === 'rejected') {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        try {
          var res = onRejected(self.data)
          if (res instanceof Promise) {
            res.then(resolve, reject)
          } else {
            resolve(res)
          }
        } catch (error) {
          reject(error)
        }
      })
    })
  }
}

function noop (a) {
  return a
}

// catch 方法
Promise.prototype.catch = function (onRejected) {
  return this.then(null, onRejected)
}