一步一步手写PromiseA+(通过PromiseA+,872个测试用例)

425 阅读15分钟

Promise简介

  1. 对于PromiseA+规范的详细描述: Promises/A+中文网
  2. 这里就不多赘述了,简单描述一下,首先我们知道Promise主要是用来处理异步任务的
  3. 它有三种状态(pending, fulfilled, rejcted), 默认初始状态为pedning
  4. Promise状态改变时(未决->已决),后续then方法才会执行对应的逻辑
  5. then方法返回一个新的Promise(简称ProThen),Prothen的状态会与调用then的Promise关联后续我们再详细展开
  6. Promise状态只能修改一次

简易版本Promise实现

  • 基本的构造函数结构
  • 简易的then方法实现

基本的构造函数结构

  1. promise传参必须是个函数(excuter)
  2. 函数是立刻调用的,函数有两个参数,且两个参数也是函数(resolve, reject)
  3. 调用resolve时 promise 状态为 fulfilled,调用reject时 promise状态为rejectedexcuter执行报错时,promise状态也为rejected

代码实现

 // 定义Promise 3种状态
 const PENDING = 'pending'
 const FULFILLED = 'fulfilled'
 const REJECTED = 'rejected'
 
 class MyPromise {
   // Promise状态
   #PromiseState = PENDING
   // Promise结果
   #PromiseResult
   
   // 修改Promise状态为拒绝
   #reject = (resason) => {
     this.#setPromiseState(REJECTED, resason)
   }

   // 修改Promise状态为成功
   #resolve = (data) => {
     this.#setPromiseState(FULFILLED, data)
   }

   // 设置Promise状态
   #setPromiseState(state, data) {
     if(this.#PromiseState !== PENDING) return
     this.#PromiseState = state
     this.#PromiseResult = data
   }
   
   // 构造函数执行
   constructor(excuter) {
     if(typeof excuter !== 'function') throw new TypeError('Promise resolver is not a function')
       try {
       excuter(this.#resolve, this.#reject) 
     } catch (error) {
       console.error(error)
       this.#reject(error)
     }
   }
 }

测试代码

    const p = new MyPromise((a, b) => {
      throw new Error(111)
      a('成功')
      b('失败')
    })
    
    const p1 = new MyPromise((a, b) => {
      a('成功')
      throw new Error(111)
      b('失败')
    })
    console.log(p)
    console.log(p1)    

小结

  1. 我们的代码做到到了改变Promise状态和值只会改一次
  2. exuter 执行报错Promise会变为rejcted状态

简易的then方法实现

  1. then函数必定返回一个新的Promise(简称ProThen

  2. then存在于构造函数的Prototype

  3. 支持链式调用(new Promise().then().then())

  4. 对于同一个Promise来说,可以无限支持promise.then,promise.then ...所以生成的Promise实例是不同的而对应的状态也并不会相同

  5. 前面说到ProThen的状态 会与调用then的Promise(简称Promise)状态相 关联, 这里我们大致展开梳理一下。

    • 5.1: then方法可传递两个参数(a, b), 且a, b都可为函数
    • 5.2: a, b 为函数情况:
      • 5.2.1: Promise状态为resolve时调用 a,为rejected时调用 b
      • 5.2.2: 调用过程中代码执行无报错时:
        • 5.2.2.1:调用 a且它的返回结果不为PromiseLikeProThen状态为resolve,结果为a的返回结果
        • 5.2.2.2:调用b且它的返回结果不为PromiseLikeProThen状态为resolve,结果为b的返回结果
        • 5.2.2.3:a或者b返回结果为PromiseLike,则ProThen状态和结果与PromiseLike保持一致
      • 5.5.3: 调用过程中代码执行报错时,ProThen状态为rejected,结果为报错原因
    • 5.3:a, b 不为函数情况:
      • 5.3.1: ProThen状态与结果与Promise保持一致
    • 5.4:对于PromiseLike解释:是一个对象或者函数,拥有then属性,且then是个函数

代码实现

class MyPromise {
  // ...忽略

  then(fulfilled, rejected) {
    // 定义一个Promise
    const promise = new MyPromise(() => {})
    // 通过 实例属性拿到对应的方法
    const resolve = promise.#resolve
    const reject = promise.#reject
    return promise
  }
}

此时遇到了问题,上述代码中resolvereject 是控制ProThen状态的函数,但是我们需要执行fulfilledrejected 来知道ProThen的是什么状态,才能通过调用resolvereject实现ProThen状态和结果的改变,应该怎么做?

  • 可以使用对象映射的方式来存储对应的逻辑,设置表示当前处理函数的状态的属性(currentState) 再通过属性描述符达到修改currentState后拿到对应的处理方式,方便后续使用
const obj = {
  //成功状态的处理逻辑, excuteFn 对应 then(a, b)的 a, b 函数, setState 对应设置ProThen状态和结果
  [FULFILLED]: {
    excuteFn: fulfilled,
    setState: resolve
  },
  // 拒绝状态的处理逻辑
  [REJECTED]: {
    excuteFn: rejected,
    setState: reject
  },
  // 默认为pending
  currentState: PENDING,

  // 后续通过访问 obj.handler 可拿到不同处理逻辑
  get handler() {
    return this[this.currentState] || {}
  }
}
  • 我们再想一想,实现了对象映射存储对应逻辑,我们应该把这个对象放在哪里呢?以什么结构再存这个对象呢?
    • 很简单,我们将对象放在调用then的Promise的实例中,并通过数组的方式存储
    • why?为什么要通过数组的方式存储呢?我们可以想一下, 前面说到对于同一个Promise,可以无限支持Promise.then, Promise.then ...,如果我们通过直接赋值的形式,那么永远只能拿到一个ProThen对应的操作逻辑,因此我们需要通过数组存储来达到目的。

具体代码实现

class MyPromise {
  // ...忽略
  // 存储PtoThen的相关逻辑
  #queueTask = []
  
  #createTask({ fulfilled, resolve, rejected, reject }) {
    return {
      //成功状态的处理逻辑, excuteFn 对应 then(a, b)的 a, b 函数, setState 对应设置ProThen状态和结果
      [FULFILLED]: {
        excuteFn: fulfilled,
        setState: resolve
      },
      // 拒绝状态的处理逻辑
      [REJECTED]: {
        excuteFn: rejected,
        setState: reject
      },
      // 默认为pending
      currentState: PENDING,

      // 后续通过访问 obj.handler 可拿到不同处理逻辑
      get handler() {
        return this[this.currentState] || {}
      }
    }
  }
  
  then(fulfilled, rejected) {
    // 定义一个Promise
    const promise = new MyPromise(() => {})
    // 通过 实例属性拿到对应的方法
    const resolve = promise.#resolve
    const reject = promise.#reject
    this.#queueTask.push(this.#createTask({
      fulfilled,
      resolve,
      rejected,
      reject
    }))
    return promise
  }
}

ProThen状态设置的执行时机

  1. 调用then方法时,且Promise状态改变的时候
  2. 当调用then方法的Promise的状态改变的时候
  3. ProThen的状态设置是放在微任务队列中触发的

注意

  • 我们向数组中添加对应的ProThen的处理逻辑时,是在调用then方法时

代码实现

class MyPromise {
  // ...忽略
  
  // 设置Promise状态
  #setPromiseState(state, data) {
    if(this.#PromiseState !== PENDING) return
    this.#PromiseState = state
    this.#PromiseResult = data
    // +新增代码
    this.#handleQueueTask()
  }
  
  then(fulfilled, rejected) {
    // 定义一个Promise
    const promise = new MyPromise(() => {})
    // 通过 实例属性拿到对应的方法
    const resolve = promise.#resolve
    const reject = promise.#reject
    this.#queueTask.push(this.#createTask({
      fulfilled,
      resolve,
      rejected,
      reject
    }))

    //+新增代码 执行queueTask队列
    this.#handleQueueTask()
    return promise
  }
  
   // 处理队任务
  #handleQueueTask() {
    // Promise状态为pending时, 不执行
    if(this.#PromiseState === PENDING) return
    // 循环ProThen任务队列, 并删除当前ProThen
    for (let i = 0; i < this.#queueTask.length;) {
      const task = this.#queueTask.shift()
      // 改变ProThen状态执行逻辑 放入微队列
      this.#runMicroTask(() => {
        this.#handleSingleTask(task)
      })
    }
  }
  
// 处理单个任务
#handleSingleTask(task) {
    // 根据Promise的状态来执行ProThen的逻辑
    const { excuteFn, setState } = this.#getHandler(task, this.#PromiseState)
    // 设置 ProThen 为成功
    const { setState: resolve } = this.#getHandler(task, FULFILLED)
    // 设置 ProThen 为拒绝
    const { setState: reject } = this.#getHandler(task, REJECTED)
    // a, b 不是函数情况, ProThen 与 Promise 状态一致
    if(typeof excuteFn !== 'function') {
      setState(this.#PromiseResult)
      return
    }

    // 执行 excuteFn函数
    try {
      const result = excuteFn(this.#PromiseResult)
      // 结果是PromiseLike情况, 让ProThen与其状态一致
      if(this.#isPromiseLike(result)) {
        result.then(resolve, reject)
      } else {
        // 结果不是PromiseLike, ProThen状态为成功
        resolve(result)
      }
    } catch (error) {
      // 执行代码报错时ProThen 为拒绝
      console.error(error)
      reject(error)
    }
  }
  
    // 判断是否为PromiseLike
  #isPromiseLike(data){ 
    return !!(data && (typeof data === 'object' || typeof data === 'function') && typeof data.then === 'function' ) 
  }

// 设置并取出对应的ProThen执行逻辑
  #getHandler(task, state) {
    task.currentState = state
    return task.handler
  }
  
 /**
 * 把任务放进微队列中执行
 * @param {Function} callback 
 * node环境中, 使用process.nextTick
 * 浏览器环境, 优先使用queueMicroTask
 * 最后, 使用 setTimeout
*/
  #runMicroTask(callback) {
    if(globalThis && globalThis.process && globalThis.process.nextTick) {
      globalThis.process.nextTick(callback)
    } else if(globalThis.queueMicrotask) {
      globalThis.queueMicrotask(callback)
    } else {
      globalThis.setTimeout(callback, 0)
    }
  }
}

此时简易的Then方法实现就已完成。

完整代码

// 定义Promise 3种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  // Promise状态
  #PromiseState = PENDING
  // Promise结果
  #PromiseResult

  // 修改Promise状态为拒绝
  #reject = (resason) => {
    this.#setPromiseState(REJECTED, resason)
  }

  // 修改Promise状态为成功
  #resolve = (data) => {
    this.#setPromiseState(FULFILLED, data)
  }

  /**
   * 把任务放进微队列中执行
   * @param {Function} callback 
   * node环境中, 使用process.nextTick
   * 浏览器环境, 优先使用queueMicroTask
   * 最后, 使用 setTimeout
   */
  #runMicroTask(callback) {
    if(globalThis && globalThis.process && globalThis.process.nextTick) {
      globalThis.process.nextTick(callback)
    } else if(globalThis.queueMicrotask) {
      globalThis.queueMicrotask(callback)
    } else {
      globalThis.setTimeout(callback, 0)
    }
  }
  

  // 设置Promise状态
  #setPromiseState(state, data) {
    if(this.#PromiseState !== PENDING) return
    this.#PromiseState = state
    this.#PromiseResult = data
    this.#handleQueueTask()
  }

  constructor(excuter) {
    if(typeof excuter !== 'function') throw new TypeError('Promise resolver is not a function')
    try {
      excuter(this.#resolve, this.#reject) 
    } catch (error) {
      console.error(error)
      this.#reject(error)
    }
  }

  // 存储PtoThen的相关逻辑
  #queueTask = []

  #createTask({ fulfilled, resolve, rejected, reject }) {
    return {
      //成功状态的处理逻辑, excuteFn 对应 then(a, b)的 a, b 函数, setState 对应设置ProThen状态和结果
      [FULFILLED]: {
        excuteFn: fulfilled,
        setState: resolve
      },
      // 拒绝状态的处理逻辑
      [REJECTED]: {
        excuteFn: rejected,
        setState: reject
      },
      // 默认为pending
      currentState: PENDING,

      // 后续通过访问 obj.handler 可拿到不同处理逻辑
      get handler() {
        return this[this.currentState] || {}
      }
    }
  }

  // 判断是否为PromiseLike
  #isPromiseLike(data){ 
    return !!(data && (typeof data === 'object' || typeof data === 'function') && typeof data.then === 'function' ) 
  }

  // 设置并取出对应的ProThen执行逻辑
  #getHandler(task, state) {
    task.currentState = state
    return task.handler
  }

  #handleSingleTask(task) {
    // 根据Promise的状态来执行ProThen的逻辑
    const { excuteFn, setState } = this.#getHandler(task, this.#PromiseState)
    // 设置 ProThen 为成功
    const { setState: resolve } = this.#getHandler(task, FULFILLED)
    // 设置 ProThen 为拒绝
    const { setState: reject } = this.#getHandler(task, REJECTED)
    // a, b 不是函数情况, ProThen 与 Promise 状态一致
    if(typeof excuteFn !== 'function') {
      setState(this.#PromiseResult)
      return
    }

    // 执行 excuteFn函数
    try {
      const result = excuteFn(this.#PromiseResult)
      // 结果是PromiseLike情况, 让ProThen与其状态一致
      if(this.#isPromiseLike(result)) {
        result.then(resolve, reject)
      } else {
        // 结果不是PromiseLike, ProThen状态为成功
        resolve(result)
      }
    } catch (error) {
      // 执行代码报错时ProThen 为拒绝
      console.error(error)
      reject(error)
    }
  }

  // 处理队任务
  #handleQueueTask() {
    // Promise状态为pending时, 不执行
    if(this.#PromiseState === PENDING) return
    // 循环ProThen任务队列, 并删除当前ProThen
    for (let i = 0; i < this.#queueTask.length;) {
      const task = this.#queueTask.shift()
      // 改变ProThen状态执行逻辑 放入微队列
      this.#runMicroTask(() => {
        this.#handleSingleTask(task)
      })
    }
  }

  then(fulfilled, rejected) {
    // 定义一个Promise
    const promise = new MyPromise(() => {})
    // 通过 实例属性拿到对应的方法
    const resolve = promise.#resolve
    const reject = promise.#reject
    this.#queueTask.push(this.#createTask({
      fulfilled,
      resolve,
      rejected,
      reject
    }))

    // 执行queueTask队列
    this.#handleQueueTask()
    return promise
  }
}

测试代码

  const p1 = new MyPromise((a, b) => {
      setTimeout(() => {
        a(1)
        b(9)
      }, 1000)
    })
    const p2 = p1.then((data) => {
      console.log(data)
      return 2
    }).then()

    const p3 = p1.then(data => {
      throw 111
    }).then((data) => {
      console.log('不会触发')
    }, (reason) => {
      console.log('触发', reason)
      return 3
    })

    const p4 = p1.then(() => {
      return new MyPromise((a, b) => {
        b(4)
      })
    })
    console.log(p1) // fuifilled 1
    console.log(p2) // fuifilled 2
    console.log(p3) // fulfilled 3
    console.log(p4) // rejcted 4

小结

  • 我们的then方法目前来说可以适用于大部分情况,对于一些特殊的场景还是有点缺陷,例如以下场景
// 对于嵌套多层 PromiseLike 情况
const p1 = new MyPromise(resolve => {
  resolve(1)
}).then(() => {
  return {
    then(a, b) {
      a({
        then(a1, b1){
          a1(2)
        }
      })
    }
  }
})
console.log(p1) 

// 对于resolve(Promise) 的情况
const p2 = new MyPromise(resolve => {
  resolve(new MyPromise(res => res(1)))
})
console.log(p2)

// 对于循环引用只身的情况
const p3 = new MyPromise(resolve => {
  resolve()
}).then(() => {
  return p3
})
console.log(p3)
  • 对于PromiseA+规范,这些问题肯定都是要解决的,因此下面我们开始解决这些问题,实现满足PromiseA+的then

PromiseA+的 then 的实现

  1. 对于它的解释,推荐查看开头的PromiseA+链接,Promises/A+中文网

修改地方

  • 对于PromiseA+的规范查看后,发现代码主要问题有以下几点需要修改和实现
  • 对于then调用返回结果是PromiseLike的处理,我们写的有点简洁了,官方明确了好几点要求,对于PromiseLike.then的调用: 1. this指向,2. then(a, b)中,a 和 b 以及 then()出错了,我们应该只执行最先执行的,忽略其他的
  • 对于是否循环引用Promise我们压根没做判断
  • 对于resolve(Promise)我们也需要修改优化

修改后的代码

class MyPromise {
 // ... 忽略
 
   constructor(excuter) {
    if(typeof excuter !== 'function') throw new TypeError('Promise resolver is not a function')
    let isInvoke = false
    try {
      // 修改 excuter
      excuter((y) => {
        if(isInvoke) return
        isInvoke = true
        this.#resolverPromise(this, y, {
          resolve: this.#resolve,
          reject: this.#reject
        })
      }, this.#reject) 
    } catch (error) {
      console.error(error)
      this.#reject(error)
    }
  }
 
 
 // + 新增代码
 /**
   * 
   * @param {Promise} promise ProThen 
   * @param {any} x resolve(a)传参, 或者 then(a, b), a, b调用的结果
   * @param {Object} param2 
   * @param { Function } resolve  设置 ProThen 成功
   * @param { Function } reject  设置 ProThen 拒绝
   * @param { Array } serialPromiseList 串行的 x 集合 (可相关代码删除, 不影响测试结果)
   */
  #resolverPromise(promise, x, { resolve, reject, serialPromiseList = [] }) {
    try {
      // 判断 Promise 与 x 是否为同一值(本质也是循环引用)
      if(promise === x) throw new TypeError('promise and x cannot refer to the same object')
      // 判断是否循环引用了Promise
      if(serialPromiseList.includes(x)) throw new TypeError('Chaining cycle detected for promise')
      // 先排除 x 不为对象和函数, 或者为null的情况
      if(typeof x !== 'object' && typeof x !== 'function' || x === null) {
        resolve(x)
        return
      }
      // 走到这说明 x 是对象 或者 函数的情况判断
      // 声明一个变量then 尝试将 x.then 赋值给then
      const then = x.then
      // 判断then是否为函数
      if(typeof then !== 'function') {
        resolve(x)
        return
      }

      // 走到这说明 then 是个函数
      // 1. 调用then并将this指向x, 并传递两个函数 (resolvePromise, rejectPromise)
      // 2. 执行then调用时出现错误, 或 resolvePromise, rejectPromise 同时被调用时,确保只会调用一次,忽略剩下的调用, (这里不进行判断逻辑也没问题, 因为在 reject 或 resolve 中也进行了判断, 保证了Promise 改变状态只会触发一次, 但是测试Promise会不通过)
      // 3. 如果 resolvePromise 以值 y 为参数被调用,则继续运行 [[Resolve]](promise, y)
      let isInvoke = false
      try {
        then.call(x, (y) => {
          if(isInvoke) return
          isInvoke = true
          this.#resolverPromise(promise, y, {
            resolve,
            reject,
            serialPromiseList: [...serialPromiseList, x]
          })
        }, (reason) => {
          if(isInvoke) return
          isInvoke = false
          reject(reason)
        })
      } catch (error) {
        if(isInvoke) return
        isInvoke = true
        console.error(error)
        reject(error)
      }
    } catch (error) {
      console.error(error)
      reject(error)
    }
  }
  
  // 创建任务
  #createTask({ promise, fulfilled, resolve, rejected, reject }) {
    return {
      [FULFILLED]: {
        // 修改代码
        excuteFn: typeof fulfilled === 'function' ? fulfilled : (data) => data,
        setState: resolve
      },
      [REJECTED]: {
        // 修改代码
        excuteFn: typeof rejected === 'function' ? rejected  : (reason) => { throw reason },
        setState: reject
      },
      currentState: PENDING,
      // + 新增代码 ProThen
      promise,
      get handler() {
        return this[this.currentState] || {}
      }
    }
  }
  
  // 处理单个任务
  #handleSingleTask(task) {
    // 根据Promise的状态来执行ProThen的逻辑
    const { excuteFn } = this.#getHandler(task, this.#PromiseState)
    // 设置 ProThen 为成功
    const { setState: resolve } = this.#getHandler(task, FULFILLED)
    // 设置 ProThen 为拒绝
    const { setState: reject } = this.#getHandler(task, REJECTED)
    // 执行 excuteFn函数
    try {
     // 执行excuteFn 拿到 结果
     const result = excuteFn(this.#PromiseResult)
     // 进行相关判断,对ProThen 进行 不同操作
     this.#resolverPromise(task.promise, result, {
      resolve,
      reject
     })
    } catch (error) {
      // 执行代码报错时ProThen 为拒绝
      console.error(error)
      reject(error)
    }
  }
}

完整代码

// 定义Promise 3种状态
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class MyPromise {
  // Promise状态
  #PromiseState = PENDING
  // Promise结果
  #PromiseResult

  // 修改Promise状态为拒绝
  #reject = (resason) => {
    this.#setPromiseState(REJECTED, resason)
  }

  // 修改Promise状态为成功
  #resolve = (data) => {
    this.#setPromiseState(FULFILLED, data)
  }

  /**
   * 把任务放进微队列中执行
   * @param {Function} callback 
   * node环境中, 使用process.nextTick
   * 浏览器环境, 优先使用queueMicroTask
   * 最后, 使用 setTimeout
   */
  #runMicroTask(callback) {
    if(globalThis && globalThis.process && globalThis.process.nextTick) {
      globalThis.process.nextTick(callback)
    } else if(globalThis.queueMicrotask) {
      globalThis.queueMicrotask(callback)
    } else {
      globalThis.setTimeout(callback, 0)
    }
  }
  

  // 设置Promise状态
  #setPromiseState(state, data) {
    if(this.#PromiseState !== PENDING) return
    this.#PromiseState = state
    this.#PromiseResult = data
    this.#handleQueueTask()
  }

  constructor(excuter) {
    if(typeof excuter !== 'function') throw new TypeError('Promise resolver is not a function')
    let isInvoke = false
    try {
      excuter((y) => {
        if(isInvoke) return
        isInvoke = true
        this.#resolverPromise(this, y, {
          resolve: this.#resolve,
          reject: this.#reject
        })
      }, this.#reject) 
    } catch (error) {
      console.error(error)
      this.#reject(error)
    }
  }

  // 存储PtoThen的相关逻辑
  #queueTask = []

  #createTask({ promise, fulfilled, resolve, rejected, reject }) {
    return {
      //成功状态的处理逻辑, excuteFn 对应 then(a, b)的 a, b 函数, setState 对应设置ProThen状态和结果
      [FULFILLED]: {
        excuteFn: typeof fulfilled === 'function' ? fulfilled : (data) => data,
        setState: resolve
      },
      // 拒绝状态的处理逻辑
      [REJECTED]: {
        excuteFn: typeof rejected === 'function' ? rejected  : (reason) => { throw reason },
        setState: reject
      },
      // 默认为pending
      currentState: PENDING,
      // promise
      promise,
      // 后续通过访问 obj.handler 可拿到不同处理逻辑
      get handler() {
        return this[this.currentState] || {}
      }
    }
  }

  // 设置并取出对应的ProThen执行逻辑
  #getHandler(task, state) {
    task.currentState = state
    return task.handler
  }

  /**
   * 
   * @param {Promise} promise ProThen 
   * @param {any} x resolve(a)传参, 或者 then(a, b), a, b调用的结果
   * @param {Object} param2 
   * @param { Function } resolve  设置 ProThen 成功
   * @param { Function } reject  设置 ProThen 拒绝
   * @param { Array } serialPromiseList 串行的 x 集合 (可相关代码删除, 不影响测试结果)
   *
   */
  #resolverPromise(promise, x, { resolve, reject, serialPromiseList = [] }) {
    try {
      // 判断 Promise 与 x 是否为同一值(本质也是循环引用)
      if(promise === x) throw new TypeError('promise and x cannot refer to the same object')
      // 判断是否循环引用了Promise
      if(serialPromiseList.includes(x)) throw new TypeError('Chaining cycle detected for promise')
      // 先排除 x 不为对象和函数, 或者为null的情况
      if(typeof x !== 'object' && typeof x !== 'function' || x === null) {
        resolve(x)
        return
      }
      // 走到这说明 x 是对象 或者 函数的情况判断
      // 声明一个变量then 尝试将 x.then 赋值给then
      const then = x.then
      // 判断then是否为函数
      if(typeof then !== 'function') {
        resolve(x)
        return
      }

      // 走到这说明 then 是个函数
      // 1. 调用then并将this指向x, 并传递两个函数 (resolvePromise, rejectPromise)
      // 2. 执行then调用时出现错误, 或 resolvePromise, rejectPromise 同时被调用时,确保只会调用一次,忽略剩下的调用, (这里不进行判断逻辑也没问题, 因为在 reject 或 resolve 中也进行了判断, 保证了Promise 改变状态只会触发一次, 但是测试Promise会不通过)
      // 3. 如果 resolvePromise 以值 y 为参数被调用,则继续运行 [[Resolve]](promise, y)
      let isInvoke = false
      try {
        then.call(x, (y) => {
          if(isInvoke) return
          isInvoke = true
          this.#resolverPromise(promise, y, {
            resolve,
            reject,
            serialPromiseList: [...serialPromiseList, x]
          })
        }, (reason) => {
          if(isInvoke) return
          isInvoke = false
          reject(reason)
        })
      } catch (error) {
        if(isInvoke) return
        isInvoke = true
        console.error(error)
        reject(error)
      }
    } catch (error) {
      console.error(error)
      reject(error)
    }
  }

  #handleSingleTask(task) {
    // 根据Promise的状态来执行ProThen的逻辑
    const { excuteFn } = this.#getHandler(task, this.#PromiseState)
    // 设置 ProThen 为成功
    const { setState: resolve } = this.#getHandler(task, FULFILLED)
    // 设置 ProThen 为拒绝
    const { setState: reject } = this.#getHandler(task, REJECTED)
    // 执行 excuteFn函数
    try {
     const result = excuteFn(this.#PromiseResult)
     this.#resolverPromise(task.promise, result, {
      resolve,
      reject
     })
    } catch (error) {
      // 执行代码报错时ProThen 为拒绝
      console.error(error)
      reject(error)
    }
  }

  // 处理队任务
  #handleQueueTask() {
    // Promise状态为pending时, 不执行
    if(this.#PromiseState === PENDING) return
    // 循环ProThen任务队列, 并删除当前ProThen
    for (let i = 0; i < this.#queueTask.length;) {
      const task = this.#queueTask.shift()
      this.#runMicroTask(() => {
        this.#handleSingleTask(task)
      })
    }
  }

  then(fulfilled, rejected) {
    // 定义一个Promise
    const promise = new MyPromise(() => {})
    // 通过 实例属性拿到对应的方法
    const resolve = promise.#resolve
    const reject = promise.#reject
    this.#queueTask.push(this.#createTask({
      promise,
      fulfilled,
      resolve,
      rejected,
      reject
    }))

    // 执行queueTask队列
    this.#handleQueueTask()
    return promise
  }
}


MyPromise.deferred = function () {
  var result = {};
  result.promise = new MyPromise(function (resolve, reject) {
    result.resolve = resolve;
    result.reject = reject;
  });
  return result;
}

module.exports = MyPromise

测试工具测试Promise

  • 下载 promises-aplus-tests 测试包
npm i promises-aplus-tests 
  • package.json 中添加脚本
  "scripts": {
    "test": "promises-aplus-tests 你的js文件"
    // 例如我的文件叫 indexTest.js
    "test": "promises-aplus-tests indexTest.js"
  },
  • MyPromise代码文件中加入以下
MyPromise.deferred = function () {
  var result = {};
  result.promise = new MyPromise(function (resolve, reject) {
    result.resolve = resolve;
    result.reject = reject;
  });
  return result;
}

module.exports = MyPromise
  • 运行脚本的js文件中
const promisesAplusTests = require('promises-aplus-tests');
const adapter = require('../index1'); // MyPromise文件路径

promisesAplusTests(adapter, function (err) {
  if (err) {
    console.error('Promises/A+ 测试失败:');
    console.error(err);
  } else {
    console.log('Promises/A+ 测试通过');
  }
});
  • 运行命令 npm run test
  • 测试通过情况

image.png

至此,PromiseA+ 规范我们全部完成,如有疑问或者错误描述的地方,可评论或者私信,我会及时修改和回复,谢谢