Promise

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

class MyPromise {
  #state = 'pending'
  #result = undefined
  #handlers = []

  constructor(executor) {
    const resolve = (data) => {
      this.#changeState(FULFILLED, data)
    }
    const reject = (reason) => {
      this.#changeState(REJECTED, reason)
    }
    try {
      executor(resolve, reject)
    } catch (err) {
      reject(err)
    }
  }

  #changeState(state, result) {
    if (this.#state !== PENDING) return
    this.#state = state
    this.#result = result
    this.#run()
  }

  #isPromiseLike(value) {
    if (
      value !== 'null' &&
      (typeof value === 'object' || typeof value === 'function')
    ) {
      return typeof value.then === 'function'
    }
    return false
  }

  #runMicroTask(func) {
    if (typeof process === 'object' && typeof process.nextTick === 'function') {
      process.nextTick(func)
    } else if (typeof MutationObserver === 'funcction') {
      const ob = new MutationObserver(func)
      const textNode = document.createTextNode('1')
      ob.observe(textNode, {
        characterData: true,
      })
      textNode.data = '2'
    } else {
      setTimeout(func)
    }
  }

  #runOne(callback, resolve, reject) {
    this.#runMicroTask(() => {
      // 1. onFulFilled或onRejected不是函数
      // 会发生值穿透
      if (typeof callback !== 'function') {
        const settled = this.#state === FULFILLED ? resolve : reject
        settled(this.#result)
        return
      }
      // 2. onFulFilled或onRejected是函数
      try {
        const data = callback(this.#result)
        if (this.#isPromiseLike(data)) {
          // 2.1 onFulFilled或onRejected调用的返回值 是PromiseLike
          data.then(resolve, reject)
        } else {
          // 2.2 onFulFilled或onRejected调用的返回值 不是PromiseLike
          resolve(data)
        }
      } catch (err) {
        reject(err)
      }
    })
  }

  #run() {
    if (this.#state === PENDING) return
    while (this.#handlers.length) {
      const { onFulfilled, onRejected, resolve, reject } =
        this.#handlers.shift()
      if (this.#state === FULFILLED) {
        this.#runOne(onFulfilled, resolve, reject)
      } else {
        this.#runOne(onRejected, resolve, reject)
      }
    }
  }

  then(onFulfilled, onRejected) {
    return new MyPromise((resolve, reject) => {
      this.#handlers.push({
        onFulfilled,
        onRejected,
        resolve,
        reject,
      })
      this.#run()
    })
  }

  catch(onRejected) {
    return this.then(undefined, onRejected)
  }

  finally(onFinally) {
    return this.then(
      (data) => {
        onFinally()
        return data
      },
      (err) => {
        onFinally()
        throw err
      }
    )
  }

  static resolve(value) {
    if (value instanceof MyPromise) return value
    let _resolve, _reject
    const p = new MyPromise((resolve, reject) => {
      _resolve = resolve
      _reject = reject
    })
    if (p.#isPromiseLike(value)) {
      value.then(_resolve, _reject)
    } else {
      _resolve(value)
    }
    return p
  }

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

参考

Last Updated: