Skip to content

实现一个Promise

js
// es5

function Promise(fn) {
  // 回调函数两个参数
  fn(
    // 成功的回调
    (data) => {
      this.success(data)
    },
    // 失败的回调
    (error) => {
      this.error()
    },
  )
}

Promise.prototype.resolve = function (data) {
  this.success(data)
}
Promise.prototype.reject = function (error) {
  this.error(error)
}
Promise.prototype.then = function (success, error) {
  this.success = success
  this.error = error
}

// 新建 myPromise.js
// 先定义3个常量表示状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// 新建 myPromise类
class myPromise {
  constructor(executor) {
    // executor是一个执行器,进入会立即执行
    // 并传入resolve和reject方法
    executor(this.resolve, this.reject)
  }
  // 储存状态的变量,初始值是pending
  status = PENDING
  // 存储成功回调函数
  onFulfilledCallback = []
  // 存储失败回调函数
  onRejectedCallback = []
  // resolve和reject为什么要用箭头函数
  // 如果直接调用的话,普通函数this指向的是window或者undefined
  // 用箭头函数就可以让this指向当前实例对象
  // 成功之后的值
  value = null
  // 失败之后的原因
  reason = null
  // 更改成功后的状态
  resolve = (value) => {
    // 只有状体是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态修改为成功
      this.status = FULFILLED
      // 保存成功之后的值
      this.value = value
      // resolve里面将所有成功的回调拿出来执行
      while (this.onFulfilledCallback.length) {
        // 取出第一个元素函数调用,直到数组为空
        this.onFulfilledCallback.shift()(value)
      }
    }
  }
  // 更改失败后的状态
  reject = (reason) => {
    // 只有状态是等待,才执行状态修改
    if (this.status === PENDING) {
      // 状态修改为失败
      this.status = REJECTED
      // 保存失败后的原因
      this.reason = reason
      // 判断失败回调是否存在,如果存在就调用
      while (this.onRejectedCallback.length) {
        this.onRejectedCallback.shift()(reason)
      }
    }
  }
  then(onFulfilled, onRejected) {
    // 判断状态
    if (this.status === FULFILLED) {
      // 调用成功回调,并把值返回
      onFulfilled(this.value)
    } else if (this.status === REJECTED) {
      // 调用失败回调,并且把原因返回
      onRejected(this.reason)
    } else if (this.status === PENDING) {
      // 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来
      // 等到执行成功失败函数的时候在传递
      this.onFulfilledCallback.push(onFulfilled)
      this.onRejectedCallback.push(onRejected)
    }
  }
}

module.exports = myPromise

简单版本

js
// ------------------------------ 构造函数实现 ------------------------
function myPromise(constructor) {
  let self = this
  // 定义状态改变前的初始状态
  self.status = 'pending'
  // 定义状态微resolved的时候的状态
  self.value = undefined
  // 定义状态为rejected的时候的状态
  self.reason = undefined
  function resolve(value) {
    if (self.status === 'pending') {
      self.value = value
      self.status = 'resolved'
    }
  }
  function reject(reason) {
    if (self.status === 'pending') {
      self.reason = reason
      self.status = 'rejected'
    }
  }
  // 捕获构造异常
  try {
    constructor(resolve, reject)
  } catch {
    reject(e)
  }
}

// 添加then方法

myPromise.prototype.then = function (onFulfilled, onRejected) {
  let self = this
  switch (self.status) {
    case 'resolved':
      onFulfilled(self.value)
      break
    case 'rejected':
      onRejected(self.reason)
      break
    default:
  }
}

const p = new myPromise(function (resolve, reject) {
  resolve(1)
})
p.then(function (x) {
  console.log(x)
})

// ---------------------------------class实现------------------------

class myPromise {
  constructor(fn) {
    this.resolvedCallbacks = []
    this.rejectCallbacks = []

    this.state = 'PENDING'
    this.value = ''

    fn(this.resolve.bind(this), this.reject.bind(this))
  }

  resolve(value) {
    if (this.state === 'PENDING') {
      this.state = 'RESOLVED'
      this.value = value
      this.resolvedCallbacks.map((cb) => cb(value))
    }
  }
  reject(value) {
    if (this.state === 'PENDING') {
      this.state = 'REJECTED'
      this.value = value
      this.rejectCallbacks.map((cb) => cb(value))
    }
  }
  then(onFulfilled, onRejected) {
    if (this.state === 'PENDING') {
      this.resolvedCallbacks.push(onFulfilled)
      this.rejectCallbacks.push(onRejected)
    }
    if (this.state === 'RESOLVED') {
      onFulfilled(this.value)
    }
    if (this.state === 'REJECTED') {
      onRejected(this.value)
    }
  }
}

如有转载或 CV 的请标注本站原文地址