Skip to content

Promise

promise基础代码实现

ts
const promiseState = {
  PENDING: 'pending',
  FULFILLED: 'fulfilled',
  REJECTED: 'rejected',
} as const

type PromiseState = (typeof promiseState)[keyof typeof promiseState]

function runMicrotask(callback: () => void) {
  if (typeof queueMicrotask === 'function') {
    queueMicrotask(callback)
  } else if (typeof process === 'object' && typeof process.nextTick === 'function') {
    // node 环境
    process.nextTick(callback)
  } else if (typeof MutationObserver === 'function') {
    const text = document.createTextNode('')
    const observer = new MutationObserver(callback)
    observer.observe(text, { characterData: true })
    text.data = '1'
  } else {
    setTimeout(callback)
  }
}

function isPromiseLike(value: any) {
  return typeof value?.then === 'function'
}

export default class MyPromise<T = unknown> {
  private state: PromiseState = promiseState.PENDING
  private result: T | undefined = undefined

  private handlers: (() => void)[] = []

  constructor(executor: (resolve: (value: T) => void, reject: (reason: any) => void) => void) {
    try {
      executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      // 如果执行器中抛出错误,则将状态设置为 rejected, 并设置错误信息
      this.reject(error)
    }
  }

  private resolve(value: T) {
    this.setState(promiseState.FULFILLED, value)
  }

  private reject(reason: any) {
    this.setState(promiseState.REJECTED, reason)
  }

  private setState(state: PromiseState, result: T | undefined) {
    // 当状态为 pending 时,才进行状态的改变
    if (this.state !== promiseState.PENDING) return
    this.result = result
    this.state = state

    this.runTasks()
  }

  private runTasks() {
    runMicrotask(() => {
      if (this.state !== promiseState.PENDING) {
        this.handlers.forEach(cb => cb())
        this.handlers = []
      }
    })
  }

  then(
    onFulfilled?: ((value: T | undefined) => void) | null | undefined,
    onRejected?: ((reason: any) => void) | null | undefined
  ) {
    // 支持链式调用,但是这里不能返回 this,因为 this是之前的 实例,状态已经被定下来了,不能再改变了。
    // 在链式调用里面是可以处理新的 promise状态的。所以需要返回一个全新的 promise 实例
    return new MyPromise((resolve, reject) => {
      // pending 状态,需要将 onFulfilled 和 onRejected 函数保存起来,等到状态改变时,再执行

      this.handlers.push(() => {
        try {
          const cb = this.state === promiseState.FULFILLED ? onFulfilled : onRejected
          const res = typeof cb === 'function' ? cb?.(this.result) : this.result

          if (isPromiseLike(res)) {
            ;(res as any).then(resolve, reject)
          } else {
            this.state === promiseState.FULFILLED ? resolve(res) : reject(res)
          }
        } catch (error) {
          reject(error)
        }
      })

      this.runTasks()
    })
  }

  catch(onRejected?: ((reason: any) => void) | null | undefined) {
    return this.then(null, onRejected)
  }

  finally(onFinally?: (() => void) | null | undefined) {
    // finally 不接受参数,把参数返回,穿透给下一个 链式调用
    return this.then(
      value => {
        onFinally?.()
        return value
      },
      error => {
        onFinally?.()
        throw error
      }
    )
  }

  /**
   * Promise.resolve() 静态方法以给定值“解决(resolve)”一个 Promise。
   * 如果该值本身就是一个 Promise,那么该 Promise 将被返回;
   * 如果该值是一个 thenable 对象,Promise.resolve() 将调用其 then() 方法及其两个回调函数;
   * 否则,返回的 Promise 将会以该值兑现。
   */
  static resolve<T>(value: T) {
    if (value instanceof Promise) {
      return value
    }

    return new Promise((resolve, reject) => {
      if (isPromiseLike(value)) {
        ;(value as any).then(resolve, reject)
      } else {
        resolve(value)
      }
    })
  }

  /**
   * Promise.reject() 静态方法返回一个以给定原因拒绝的 Promise。
   */
  static reject(reason: any) {
    return new Promise((_, reject) => {
      reject(reason)
    })
  }

  static try(fn: (...args: any[]) => any, ...args: any[]) {
    return new Promise(resolve => {
      // 这里执行如果报错的话,会自动将错误信息 reject 出去,参考 constructor 中 executor 的执行
      resolve(fn(...args))
    })
  }

  static all<T extends readonly unknown[] | []>(value: T) {
    // 将 value 转化为数组
    const promises = [...value]
    // 返回 promise
    return new MyPromise((resolve, reject) => {
      // 声明一个数组,用来保存resolve 的结果
      const results: T[] = []

      // 数组长度为0 直接返回空数组
      if (promises.length === 0) {
        resolve([])
      }

      // 声明一个计数器,用来记录 执行的 promise 成功的 数量
      let count = 0

      // 遍历数组,执行每一个
      promises.forEach((promise, index) => {
        console.log(index)

        // 将所有 promise 转为 Promise ,因为有可能 传递的 value 是 [1,2,promise] 这种
        MyPromise.resolve(promise).then(res => {
          // 将结果保存起来,如果全部成功,则 resolve 出去
          results[index] = res
          count++

          if (count === promises.length) {
            resolve(results)
          }

          // 失败的话直接执行 reject 就行了
        }, reject)
      })
    })
  }
}