手写 Promise 链式调用的实现

1,115 阅读2分钟

我觉得实现 Promise,最难的部分是链式调用。下面是 Promise 链式调用的例子:

(new Promise(resolve => {
  resolve(1)
})).then(data => {
  console.log(data)
  return new Promise(
    resolve => setTimeout(() => resolve(2), 100)
  )
}).then(data => {
  console.log(data)
  return Promise.resolve(3)
}).then(data => console.log(data))

上面代码会依次输出: 1,2,3。链式调用就是一个个按顺序执行异步操作,把上一个 Promise 中 then 中的返回的数据,传递到到下一个 Promise 中。往下看前,大家可以试试看自己实现下 Promise 链式调用。

实现

1 支持非链式调用

我们先来实现个非链式调用的 MyPromise,满足下面的调用:

// 情况1: 输出 1。
(new MyPromise(resolve => {
  resolve(1)
})).then(data => console.log(data));

// 情况2: 输出 2。
(new MyPromise(resolve => {
   setTimeout(() => resolve(2), 100)
})).then(data => console.log(data))

实现代码如下:

const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'

class MyPromise {
  constructor(fn) {
    this.status = PENDING
    this.data = null
    fn(this._resolve.bind(this))
  }

  _resolve(data) {
    if (this.status === PENDING) {
      this.status = FULFILLED
      this.data = data
      this.callback && this.callback(data)
    }
  }

  then(fulfilledCallback) {
    switch (this.status) {
      case PENDING:  // 针对情况1
        this.callback = fulfilledCallback
        break;
      case FULFILLED: // 针对情况2
        fulfilledCallback(this.data)
        break;
    }
  }
}

2 支持链式调用

满足下面的调用:

// 依次输出:1,2,3
(new MyPromise(resolve => {
  resolve(1)
})).then((data) => {
  console.log(data)
  return new MyPromise(
    resolve => setTimeout(() => resolve(2), 100)
  )
}).then((data) => {
  console.log(data)
  return 
}).then((data) => {
  console.log(data)
})

要支持链式调用,then 中返回的也应该是个 MyPromise 对象。并且返回的 MyPromise 对象要接上回调里的另一个 MyPromise 对象。只需改写 then 函数。代码实现如下:

then(fulfilledCallback) {
  return new MyPromise((resolve, reject) => {
    const fulfilled = () => {
    const res = fulfilledCallback(this.data)
      return this.resolvePromise(res, resolve, reject)
    }

    switch (this.status) {
      case PENDING:
        this.callback = fulfilled
        break;
      case FULFILLED:
        fulfilled()
        break;
    }
  })
}

resolvePromise(fulfillRes, resolve, reject) {
  if(fulfillRes instanceof MyPromise) {
    // 把 resolve 的 data 往下传
    fulfillRes.then(resolve, reject)
  } else {
    resolve(fulfillRes)
  }
}

以上,就实现了 Promise 的链式调用。完整代码如下:

const PENDING = 'PENDING'
const FULFILLED = 'FULFILLED'
class MyPromise {
  constructor(fn) {
    this.status = PENDING
    this.data = null
    fn(this._resolve.bind(this))
  }

  _resolve(data) {
    if (this.status === PENDING) {
      this.status = FULFILLED
      this.data = data
      this.callback && this.callback(data)
    }
  }

  then(fulfilledCallback) {
    return new MyPromise((resolve, reject) => {
      const fulfilled = () => {
        const res = fulfilledCallback(this.data)
        return this.resolvePromise(res, resolve, reject)
      }

      switch (this.status) {
        case PENDING:
          this.callback = fulfilled
          break;
        case FULFILLED:
          fulfilled()
          break;
      }
    })
  }

  // 实现链式的核心的代码
  resolvePromise(fulfillRes, resolve, reject) {
    if(fulfillRes instanceof MyPromise) {
      // 把 resolve 的 data 往下传
      fulfillRes.then(resolve, reject)
    } else {
      resolve(fulfillRes)
    }
  }
}

推荐阅读

《从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节》: juejin.cn/post/694531… 。该文章详细讲了 Promise 的实现。