来一次手写Promis(按照ES6规范)

356 阅读4分钟

初始化构造函数

我们都知道Promise都有三种状态 pendingfulfilledrejected,不仅有状态还有一个唯一的结果值,不管是fulfilled还是reject都会有值,而且参数(也就是我们传入的executor)会立即同步的执行,并给 executor 传入两个函数参数(resolve,reject),resolvereject函数是用来改变Promise的状态的,很重要!!!

注意:executor 在执行的期间如果发生异常,会直接reject

const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
const PENDING = 'pending'

class MyPromise2 {
  constructor(executor) {
    this.state = PENDING
    this.value = undefined
    try {
      // 绑定this,因为后面_resolve和_reject都会修改实例的状态,所以this需要是当前实例
      executor(this._resolve.bind(this), this._resolve.bind(this))
    } catch (error) {
      this._resolve(error)
    }
  }
  _resolve(data) {}
  _reject(reason) {}
}

改变状态的函数

resolve和reject都有类似的行为,所以抽取一下函数

class MyPromise2 {
  constructor(executor) {
    this.state = PENDING
    this.value = undefined
    try {
      executor(this._resolve.bind(this), this._resolve.bind(this))
    } catch (error) {
      this._resolve(error)
    }
  }
  _changeState(state, value) {
    this.state = state
    this.value = value
  }
  _resolve(data) {
    this._changeState(FULFILLED, data)
  }
  _reject(reason) {
    this._changeState(REJECTED, reason)
  }
}

then函数的初始化

我们得知道then到底是做什么的。首先肯定是返回一个新的Promise实例,因为then可以进行链式调用,然后是then函数里的两个状态的回调函数(onFulfilled,onRejected)什么时候执行。同一个Promise实例注册then的回调函数会只有一对吗。看以下代码:

const p = new MyPromise2((resolve, reject) => {
  resolve(123)
})

p.then(console.log,console.log)

p.then(
  function (data) {
    console.log(data)
  },
  function (err) {
    console.log(err)
  }
)

上面代码可不是链式调用,是同一个Promise实例注册then的回调函数有多个。至少从现在看来,我们明确then的回调函数肯定会加入到一个执行任务的队列中。啥时候执行呢?肯定是状态已决时,也就是调用resolve或reject。 总结一下:

  1. 返回新的Promise实例
  2. 回调函数不会立即执行,而是状态已决时,也就是调用resolve或reject函数时
  3. 回调函数不一定只注册一对,所以肯定有一个执行的队列。
class MyPromise2 {
  constructor(executor) {
    //...
    // 我这里是用一个数组来表示成功和失败回调函数的执行队列
    // 当然也可以用两个数组,一个表示成功的队列,一个表示失败的队列
    this.handlers = []
    // ...
  }
  // ...
  _pushHandler(executor, state) {
    this.handlers.push({
      executor,
      state,
    })
  }
  then(onFulfilled, onRejected) {
    return new MyPromise2((resolve, reject) => {
  // 因为我上面只用一个数组来表示执行队列,所以需要加一个状态,用来区分当前函数是成功时执行还是失败时执行
      this._pushHandler(onFulfilled, FULFILLED)
      this._pushHandler(onRejected, REJECTED)
    })
  }
}

then函数的链式调用

我们上面已经返回一个新的实例了,是不是说已经实现了链式调用呢?不是,还有一点就是后面的then函数的执行队列啥时候执行呢?看以下代码:

const p = new MyPromise2((resolve, reject) => {
  // setTimeout(() => {
  resolve(123)
  // })
})

const p2 = p.then(
  function A1(data) {
    console.log(data)
  },
  function B1(err) {
    console.log(err)
  }
)
p2.then(console.log, console.log)

p2里面的handlers啥时候执行呢,then函数肯定会把回填函数加入handlers。执行一定是状态发生了改变,那么P2的状态由谁来改变呢?按照规范,是由p的状态下执行的回调函数来决定,也就是A1和B1其中一个。 简单来说,假设p的状态是fulfill1ed,那个p2的状态就由A1函数决定,如果A1在执行过程中,没有发生异常,那么p2的状态也是fulfill1ed的,也就会执行p2的成功的队列,反之依然。这就是链式调用。 所以我们在_pushHandler的时候还要把then返回的新实例的 resolve 和 reject加入进去,方便我们执行A1或B1的时候可以调用 当前then函数返回新实例的resolve或reject,改变p2的状态。

  _pushHandler(executor, state, resolve, reject) {
   this.handlers.push({
      executor,
      state,
      resolve,
      reject,
    })
  }

  then(onFulfilled, onRejected) {
    return new MyPromise2((resolve, reject) => {
      this._pushHandler(onFulfilled, FULFILLED, resolve, reject)
      this._pushHandler(onRejected, REJECTED, resolve, reject)
    })
  }

队列的执行Timing

执行时机发生在状态改变时,也就是我们的_changeState函数,还有就是then函数执行时

 _changeState(state, value) {
    this.state = state
    this.value = value
    // 加入运行handlers的逻辑
 }
_runHandlers() {
    if (this.state === PENDING) return
    while (this.handlers.length) {
    // 取出队列首的任务
      this._runOneHandler(this.handlers.shift())
    }
  }
  _runOneHandler({ executor, state, resolve, reject }) {
    if (this.state !== state) return
    // 放到微任务队列去执行
    queueMicrotask(() => {
      // 不是函数,那么then返回的promise的状态就和当前promise的状态保持一致
      if (typeof executor !== 'function') {
        this.state === FULFILLED ? resolve(this.value) : reject(this.value)
        return
      }
      try {
        const result = executor(this.value)
        // 如果是回调函数返回的是一个Promise
        if (result instanceof MyPromise) {
        // then函数返回的Promise的状态由他决定
          result.then(resolve, reject)
          return
        }
        // 正常走逻辑
        resolve(result)
      } catch (error) {
        reject(error)
      }
    })
  }
   then(onFulfilled, onRejected) {
    return new MyPromise2((resolve, reject) => {
      this._pushHandler(onFulfilled, FULFILLED, resolve, reject)
      this._pushHandler(onRejected, REJECTED, resolve, reject)
      this._runHandlers()
    })
  }