手写Promise

112 阅读2分钟

写这篇文章的初衷

  • 了解Promise的内部执行机制
  • 尝试封装一个mini版Promise

原生Promise使用

image.png

看出来了这里需要接收一个函数,像这样:

image.png

  1. Promise是一个构造函数,原型上绑定三个静态属性分别为then、catch、finally这几个静态方法
  2. 构造函数实例也有这几个钩子函数

开始封装

  • 这里主要解释下代码执行机制
  • 注释部分解释

// @ts-nocheck

class Promise2 {
  //默认是pending状态
  state = "pending"
  //缓存因为异步执行函数
  /**
  * 像这样 new Promise((resolve,reject) => {
  * setTimeout()
  *  resolve()
  * })
  *
  */
  callbacks = []

  private resolveOrReject(state, data, i) {
  // 初始状态state是pending
    if (this.state !== "pending") return
    this.state = state
    //nextTick 是我手写的异步调用栈,会在浏览器主线程执行完毕后触发
    //你可以理解Promise.then触发后 最后会走到这里,并且它总会在最后执行
    nextTick(() => {
      this.callbacks.forEach(handle => {
        if (typeof handle[i] === "function") {
          let x
          try {
            x = handle[i].call(undefined, data)
          } catch (e) {
            return handle[2].reject(e)
          }
          handle[2].resolveWith(x)
        }
      })
    })
  }
  /**
  * 核心方法执行 resolveOrReject这个方法
  */
  private resolve(result) {
    this.resolveOrReject("fulfilled", result, 0)
  }
  private reject(reason) {
    this.resolveOrReject("rejected", reason, 1)
  }

  constructor(fn) {
    if (typeof fn !== "function") {
    //构造函数默认必须接收一个函数、否则报错
      throw new Error("The argument must be a function type!");
    }
    //执行传入的函数
    /**
    * new Promise((resolve, reject) => {})
    * this.resolve.bind(this) ===> resolve
    * this.reject.bind(this) ===> reject
    */
    fn(this.resolve.bind(this), this.reject.bind(this))
  }
  
  // then接收两个非必填函数参数、并缓存到一个临时数组中
  //最终为返回一个新的Promise实例
  then(succeed?, fail?) {
    const handle = []
    if (typeof succeed === "function") {
      handle[0] = succeed
    }
    if (typeof fail === "function") {
      handle[1] = fail
    }
    
    // new Promise2(() => {}) 这里也是一个hack,会触发上面的构造器 ---> resolveOrReject(resolveOrReject会等到下面逻辑都执行完才会触发)
    handle[2] = new Promise2(() => {})
    
    //缓存到数组中方便下一个循环执行
    this.callbacks.push(handle)
    
    //这样做就可以链式调用
    return handle[2]
  }
  private resolveWithSelf() {
    this.reject(new TypeError())
  }
  private resolveWithPromise(x) {
    x.then(
      result => { this.resolve(result) },
      reason => { this.reject(reason) }
    )
  }
  private getThen(x) {
    let then
    try {
      then = x.then
    } catch (e) {
      return this.reject(e)
    }
    return then
  }
  private resolveWithThenable(x) {
    try {
      x.then(
        y => { this.resolveWith(y) },
        r => { this.reject(r) }
      )
    } catch (e) {
      this.reject(e)
    }
  }
  
  /**
   * 解决new Promise(() => {}).then(res => {
   * return {
   *    e.g 1 返回普通对象
   *    e.g 2 返回Promise对象
   * }
   * 目的是链式调用
   * })
   */
  private resolveWithObject(x) {
    let then = this.getThen(x)
    if (then instanceof Function) {
      this.resolveWithThenable(x)
    } else {
      this.resolve(x)
    }
  }
  
  //对resolve() 或者 reject() 返回值进行二次处理
  private resolveWith(x) {
    if (this === x) {
      this.resolveWithSelf()
    } else if (x instanceof Promise2) {
      this.resolveWithPromise(x)
    } else if (x instanceof Object) {
      this.resolveWithObject(x)
    } else {
      this.resolve(x)
    }
  }
}

export default Promise2


// 封装的异步调用方法
function nextTick(fn) {
  if (process !== undefined && typeof process.nextTick === "function") {
    return process.nextTick(fn)
  } else {
    var counter = 1
    var observer = new MutationObserver(fn)
    var textNode = document.createTextNode(String(counter))

    observer.observe(textNode, {
      characterData: true
    })

    counter = counter + 1
    textNode.data = String(counter)
  }
}

最后欢迎留言交流