Skip to content
On this page

宏任务方式实现 Promise

js
const MyPromise = (() => {
  const PENDING = Symbol('pending'),
    RESOLVED = Symbol('resolved'),
    REJECTED = Symbol('rejected'),
    PromiseValue = Symbol('PromiseValue'), // 状态数据
    PromiseStatus = Symbol('PromiseStatus'), // promise 状态
    thenables = Symbol('thenables'), // thenables 状态的 promise 列表
    catchables = Symbol('catchbles'), // catchables 状态的 promise 列表
    changeStatus = Symbol('changeStatus'), // 当前状态
    settleHandle = Symbol('settleHandle'), // 后续处理的通用函数
    linkPromise = Symbol('linkPromise') // 创建串联的Promise

  return class _MyPromise {
    /**
     * 改变当前Promise的状态
     * @param {*} newStatus
     * @param {*} newValue
     * @param {*} queue 执行的作业队列
     */
    [changeStatus](newStatus, newValue, queue) {
      if (this[PromiseStatus] !== PENDING) {
        //状态无法变更
        return
      }
      this[PromiseStatus] = newStatus
      this[PromiseValue] = newValue
      //执行相应队列中的函数
      queue.forEach(handler => handler(newValue))
    }

    /**
     * @param {*} executor 未决阶段(pending状态)下的处理函数
     */
    constructor(executor) {
      this[PromiseStatus] = PENDING
      this[PromiseValue] = undefined
      this[thenables] = [] //后续处理函数的数组 -> resolved
      this[catchables] = [] //后续处理函数的数组 -> rejected

      const resolve = data => {
        this[changeStatus](RESOLVED, data, this[thenables])
      }

      const reject = reason => {
        this[changeStatus](REJECTED, reason, this[catchables])
      }
      try {
        executor(resolve, reject)
      } catch (err) {
        reject(err)
      }
    }

    /**
     * 处理 后续处理函数
     * @param {*} handler 后续处理函数
     * @param {*} immediatelyStatus 需要立即执行的状态
     * @param {*} queue 作业队列
     */
    [settleHandle](handler, immediatelyStatus, queue) {
      if (typeof handler !== 'function') {
        return
      }
      if (this[PromiseStatus] === immediatelyStatus) {
        //直接运行
        setTimeout(() => {
          handler(this[PromiseValue])
        }, 0)
      } else {
        queue.push(handler)
      }
    }

    [linkPromise](thenalbe, catchable) {
      function exec(data, handler, resolve, reject) {
        try {
          const result = handler(data) //得到当前Promise的处理结果
          if (result instanceof _MyPromise) {
            result.then(
              d => {
                resolve(d)
              },
              err => {
                reject(err)
              }
            )
          } else {
            resolve(result)
          }
        } catch (err) {
          reject(err)
        }
      }

      return new _MyPromise((resolve, reject) => {
        this[settleHandle](
          data => {
            exec(data, thenalbe, resolve, reject)
          },
          RESOLVED,
          this[thenables]
        )

        this[settleHandle](
          reason => {
            exec(reason, catchable, resolve, reject)
          },
          REJECTED,
          this[catchables]
        )
      })
    }

    then(thenable, catchable) {
      return this[linkPromise](thenable, catchable)
    }

    catch(catchable) {
      return this[linkPromise](undefined, catchable)
    }

    static all(proms) {
      return new _MyPromise((resolve, reject) => {
        const results = proms.map(p => {
          const obj = {
            result: undefined,
            isResolved: false
          }
          p.then(
            data => {
              obj.result = data
              obj.isResolved = true
              //判断是否所有的全部完成
              const unResolved = results.filter(r => !r.isResolved)
              if (unResolved.length === 0) {
                //全部完成
                resolve(results.map(r => r.result))
              }
            },
            reason => {
              reject(reason)
            }
          )
          return obj
        })
      })
    }

    static race(proms) {
      return new _MyPromise((resolve, reject) => {
        proms.forEach(p => {
          p.then(
            data => {
              resolve(data)
            },
            err => {
              reject(err)
            }
          )
        })
      })
    }

    static resolve(data) {
      if (data instanceof _MyPromise) {
        return data
      } else {
        return new _MyPromise(resolve => {
          resolve(data)
        })
      }
    }

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

MIT