Skip to content

手写 Promise 核心

我们实现一个简单的Promise,来加强对 Promise 的理解

最终效果
js
class MyPromise {
  static PENDING = 'pending'
  static FULFILLED = 'fulfilled'
  static REJECTED = 'rejected'

  constructor(executor) {
    this.status = MyPromise.PENDING
    this.value = null
    this.callbacks = []

    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    }
    catch (error) {
      this.reject(error.message)
    }
  }

  resolve(value) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.FULFILLED
      this.value = value

      setTimeout(() => {
        this.callbacks.forEach((callback) => {
          callback.onFulfilled(value)
        })
      })
    }
  }

  reject(reason) {
    if (this.status === MyPromise.PENDING) {
      this.status = MyPromise.REJECTED
      this.value = reason

      setTimeout(() => {
        this.callbacks.forEach((callback) => {
          callback.onRejected(reason)
        })
      })
    }
  }

  then(onFulfilled, onRejected) {
    if (typeof onFulfilled !== 'function')
      onFulfilled = () => this.value

    if (typeof onRejected !== 'function')
      onRejected = () => this.value

    const promise = new MyPromise((resolve, reject) => {
      if (this.status === MyPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: (value) => {
            const result = onFulfilled(value)
            this.parse(promise, result, resolve, reject)
          },

          onRejected: (reason) => {
            const result = onRejected(reason)
            this.parse(promise, result, resolve, reject)
          },
        })
      }

      if (this.status === MyPromise.FULFILLED) {
        setTimeout(() => {
          const result = onFulfilled(this.value)
          this.parse(promise, result, resolve, reject)
        })
      }

      if (this.status === MyPromise.REJECTED) {
        setTimeout(() => {
          const result = onRejected(this.value)
          this.parse(promise, result, resolve, reject)
        })
      }
    })

    return promise
  }

  parse(promise, result, resolve, reject) {
    if (promise == resolve)
      throw new TypeError('Chaining cycle detected for promise #<MyPromise>')

    try {
      if (result instanceof MyPromise)
        result.then(resolve, reject)
      else
        resolve(result)
    }
    catch (error) {
      reject(error)
    }
  }

  static resolve(value) {
    return new MyPromise((resolve, reject) => {
      if (value instanceof MyPromise)
        value.then(resolve, reject)
      else
        resolve(value)
    })
  }

  static reject(reason) {
    return new MyPromise((resolve, reject) => {
      reject(reason)
    })
  }

  static all(promises) {
    return new MyPromise((resolve, reject) => {
      const result = []
      let count = 0
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (value) => {
            result[i] = value
            count++
            if (count === promises.length)
              resolve(result)
          },
          (reason) => {
            reject(reason)
          }
        )
      }
    })
  }

  static race(promises) {
    return new MyPromise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (value) => {
            resolve(value)
          },
          (reason) => {
            reject(reason)
          }
        )
      }
    })
  }
}