Promise实现

159 阅读2分钟

talk is cheap, show me the code

const Pendding = Symbol('Pendding')
const Fulfilled = Symbol('Fulfilled')
const Rejected = Symbol('Rejected')

class Promise {
  status = Pendding
  value = undefined
  reason = undefined
  resQueue = []
  rejQueue = []
  constructor(fn) {
    try {
      fn(this.resolve.bind(this), this.reject.bind(this))
    } catch (e) {
      this.reject(e)
    }
  }
  resolve(value) {
    if (this.status !== Pendding) return

    this.status = Fulfilled
    this.value = value
    while (this.resQueue) this.resQueue.shift()(value)
  }
  reject(reason) {
    if (this.status !== Pendding) return

    this.status = Rejected
    this.reason = reason
    while (this.rejQueue) this.rejQueue.shift()(reason)
  }

  then(resCb, rejCb) {
    let _this = this
    let promise2 = new Promise((resolve, reject) => {
      let resCbTask = (value) => {
        try {
          resCb(value) // 本次回调
          resolve(value) // 传递值给下一个promise
        } catch (e) {
          reject(e)
        }
      }
      let rejCbTask = (reason) => {
        try {
          rejCb(reason)
          reject(reason)
        } catch (e) {
          reject(e)
        }
      }
      // 上一个resolve或reject是异步调用
      if (_this.status === Pendding) { 
        _this.resQueue.push(queueMicrotask(resCbTask)) // 微任务
        _this.rejQueue.push(queueMicrotask(rejCbTask))
        return
      }
      // 上一个reject是同步调用
      if (_this.status === Rejected) {
        queueMicrotask(()=> rejCbTask(_this.reason)) // 微任务
        return
      }
      // 上一个resolve是同步调用
      if (_this.status === Fulfilled) {
        queueMicroTask(()=>resCbTask(_this.value)) // 微任务
      }
  })
  return promise2
}

  static resolve(value) {
    // 开启微任务
    queueMicrotask(() => new Promise((resolve) => resolve(value)))
  }
  static reject(reason) {
    queueMicrotask(() => new Promise((reject) => reject(reason)))
  }

  // 返回所有resolve的promise,否则reject
  static all(promises) {
    // 所有promise resolve后返回结果数组,非promise直接resolve
    // 若有一个reject直接reject
    return new Promise((resolve, reject) => {
      let ret = []
      let n = 0
      function handle(res, i) {
        ret[i] = res
        n++
        if (n === promises.length) resolve(ret)
      }
      promises.forEach((promise, idx) => {
        if (!promise instanceof Promise) return handle(promise, idx)
        promise.then(res => handle(res, idx), e => reject(e))
      })
    })
  }
  // 返回第一个resolve的promise,若有一个reject立刻reject
  static race(promises) {
    return new Promise((resolve, reject) => {
      for (let promise of promises) {
        if (!promise instanceof Promise) return resolve(promise)
        promise.then(res => resolve(res), e => reject(e))
      }
    })
  }
  // 返回所有promise,无论结果是resolve还是reject
  static allSettled(promises) {
    return new Promise((resolve, _) => {
      let ret = []
      let n = 0
      function handle(promise, i, status) {
        ret[i] = { status, value: promise }
        n++
        if (n === promises.length) resolve(ret)
      }
      promises.forEach((promise, idx) => {
        if (!promise instanceof Promise) return handle(promise, idx, 'fulfilled')
        promise.then(res => handle(res, idx, 'fulfiiled'), e => handle(e, idx, 'rejected'))
      })
    })
  }
  // 和race唯一的区别是有reject先跳过,争取找到任何一个可以resolve的promise
  static any(promises) {
    return new Promise((resolve, reject) => {
      let rejects = []
      let count = 0
      for (let promise of promises) {
        if (!promise instanceof Promise) return resolve(promise)
        promise.then(
          (res) => resolve(res),
          (e) => {
            rejects.push(e)
            count++
            if (count === promises.length) reject(rejects) // 全部GG
          }
        )
      }
    })
  }
}

参考

1.从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节

2.Promises/A+规范(中文翻译)

3.看了就会,手写Promise原理,最通俗易懂的版本!!!