js手写PromiseA+规范和六个静态方法

首先回顾一下原生Promise的使用:

const promise = new Promise((resolve, reject)=>{
    resolve(true)
})
promise.then(
(result)=>{
    console.log(result) // true
},
(reason)=>{
    console.log(reason)
})

 通过Promise构造函数new了一个实例,传入一个函数 函数入参为成功和失败的两个函数resolve和reject分别传入Promise成功的值和失败的拒因(失败的字符串或error对象) 等resolve/reject执行后拿到结果,执行promise.then传入的成功/失败的回调 所以promise.catch===promise.then(null,(reason)=>{})

对于then传入的第二个函数可能会有疑惑,其实then有两个参数,第一个是resolve成功的回调,第二个是reject失败的回调 实际开发只用第一个不建议写第二个参数 也是推荐的写法 reject回调推荐再.catch一下

再看下PromiseA+规范术语:

 我们要写的MyPromise是一个构造函数/类,实例化时传入一个函数,函数里resolve和reject函数,然后类里有一个then方法,写一个promise初始雏形:

function MyPromise(executor) {
  // 定义promise成功的resolve方法
  function resolve(result) {}
  // 定义promise失败的reject方法
  function reject(reason) {}
  // then方法
  this.then = function (onFulfilled, onRejected) {}
  // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将onFulfilled方法和onRejected方法传入
  executor && executor(resolve.bind(this), reject.bind(this))
}

这里的resolve和reject额外绑定this是因为在实际调用处上下文不在MyPromise中而是在new MyPromise((resolve)=>{resolve()}) 所以this指向会跟丢 手动指回来

第二个术语:Promise的状态

 promise创建后有三个状态可供转换,它们之间的关系为:

 所以我们可以定义三个状态来表示:

const PromiseState = {
  PENDING: 'pending', // 等待态
  FULFILLED: 'fulfilled', // 完成态
  REJECT: 'reject', // 拒绝态
}

当resolve/reject时,当前状态为pending等待态时修改对应的状态并存储结果/拒因,在then方法中判断对应状态执行对应resolve/reject回调,于是有了以下代码:

function MyPromise(executor) {
  let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  let promiseResult = null // 定义promise结果 初始为null
  // 定义promise成功的resolve方法
  function resolve(result) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.FULFILLED
      promiseResult = result
    }
  }
  // 定义promise失败的reject方法
  function reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.REJECT
      promiseResult = reason
    }
  }
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      onFulfilled(promiseResult)
    }
    if (promiseState === PromiseState.REJECT) {
      onRejected(promiseResult)
    }
  }
  // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
  executor && executor(resolve.bind(this), reject.bind(this))
}

测试一下MyPromise执行能否在then里拿到resolve的值

const promise = new MyPromise((res) => {
  console.log('初始化promise')
  res(1)
})
promise.then(
  (res) => {
    console.log('then-resolve执行了', res)
  },
  (rej) => {
    console.log('then-reject执行了', rej)
  }
)

 到这里一个promise已经跑通了,尝试在executor中抛出一个错误:

const promise = new MyPromise((res) => {
  console.log('初始化promise')
  throw new Error('executor抛出的错误')
  res(1)
})
promise.then(
  (res) => {
    console.log('then-resolve执行了', res)
  },
  (reason) => {
    console.log('then-reject执行了', reason.message)
  }
)

控制台打印了一个Uncaught Error , then方法的resolveCallback没能执行 预期这个错误应该是被我们捕捉的 catch一下executor执行错误 catch里直接走reject方法:

function MyPromise(executor) {
  let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  let promiseResult = null // 定义promise结果 初始为null
  // 定义promise成功的resolve方法
  function resolve(result) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.FULFILLED
      promiseResult = result
    }
  }
  // 定义promise失败的reject方法
  function reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.REJECT
      promiseResult = reason
    }
  }
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      onFulfilled(promiseResult)
    }
    if (promiseState === PromiseState.REJECT) {
      onRejected(promiseResult)
    }
  }
  // 如果executor执行报错则catch底层错误直接走reject
  try {
    // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
    executor && executor(resolve.bind(this), reject.bind(this))
  } catch (error) {
    reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
  }
}

catch后控制台打印没有未捕获的报错了:

错误抓到了 then方法的reject回调成功执行 拿到了拒因 到这错误捕捉完成!

给then传参不是函数时,预期会报错onFulfilled不是一个函数:

PromiseA+对executor的两个入参要求:

也就是要进行参数校验 如果传的不是函数就要忽略,这里的忽略不是不管了,如果onFulfilled不是函数则将result原地返回 如果onRejected不是函数则抛出拒因 保证promise.then能预期执行:

function MyPromise(executor){
    ...
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 参数校验
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      onFulfilled(promiseResult)
    }
    if (promiseState === PromiseState.REJECT) {
      onRejected(promiseResult)
    }
  }
}
const promise = new MyPromise((res, rej) => {
  rej(new Error('默认reject抛出的error'))
})
promise.then((res) => res, undefined)

 控制台抛出了错误 我们提供的默认throw reason在不提供onRejected时生效了

当前代码完整实现:

const PromiseState = {
  PENDING: 'pending', // 等待态
  FULFILLED: 'fulfilled', // 完成态
  REJECT: 'reject', // 拒绝态
}

function MyPromise(executor) {
  let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  let promiseResult = null // 定义promise结果 初始为null
  // 定义promise成功的resolve方法
  function resolve(result) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.FULFILLED
      promiseResult = result
    }
  }
  // 定义promise失败的reject方法
  function reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.REJECT
      promiseResult = reason
    }
  }
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 参数校验
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      onFulfilled(promiseResult)
    }
    if (promiseState === PromiseState.REJECT) {
      onRejected(promiseResult)
    }
  }
  // 如果executor执行报错则catch底层错误直接走reject
  try {
    // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
    executor && executor(resolve.bind(this), reject.bind(this))
  } catch (error) {
    reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
  }
}

 这个阶段的promise并不支持异步,看下面代码输出:

console.log(1)
const promise = new MyPromise((res, rej) => {
  console.log(2)
  res(3)
})
console.log(4)
promise.then((res) => {
  console.log(res)
})
console.log(5)

原生promise的输出:

 then里的3应该是最后输出的 因为他是异步的 PromiseA+对此的叙述:

 onFulfilled和onRejected必须是在then方法被调用的那一轮事件循环之后的新执行栈中执行,也就是要放进一个事件队列等执行栈中的同步代码执行完再执行 js里实现这种机制用微任务/宏任务实现,本文用微任务实现

function MyPromise(executor){
  ...
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 参数校验
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      // 将onFulfilled放入微任务队列
      queueMicrotask(() => {
        onFulfilled(promiseResult)
      })
    }
    if (promiseState === PromiseState.REJECT) {
      // 将onRejected放入微任务队列
      queueMicrotask(() => {
        onRejected(promiseResult)
      })
    }
  }
}

3最后输出 then异步执行了!现在then是异步执行的了 如果executor中resolve也是在异步上下文中执行的,那就出问题了

function MyPromise(executor) {
  let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  let promiseResult = null // 定义promise结果 初始为null
  // 定义promise成功的resolve方法
  function resolve(result) {
    console.log('resolve执行了')
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.FULFILLED
      promiseResult = result
    }
  }
  // 定义promise失败的reject方法
  function reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.REJECT
      promiseResult = reason
    }
  }
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 参数校验
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      console.log('onFulfilled执行了')
      queueMicrotask(() => {
        onFulfilled(promiseResult)
      })
    }
    if (promiseState === PromiseState.REJECT) {
      queueMicrotask(() => {
        onRejected(promiseResult)
      })
    }
  }
  // 如果executor执行报错则catch底层错误直接走reject
  try {
    // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
    executor && executor(resolve.bind(this), reject.bind(this))
  } catch (error) {
    reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
  }
}
console.log(1)
const promise = new MyPromise((res, rej) => {
  console.log(2)
  setTimeout(() => {
    res(3)
  })
})
console.log(4)
promise.then((res) => {
  console.log(res)
})
console.log(5)

将resolve放入微任务队列后的输出:

 只有resolve执行了 then的onFulfilled没有执行导致3没有被打印 原因就在于resolve是异步执行的 所以执行then时promiseState还是pending状态并没有转变为fulfilled 导致if中的微任务执行onFulfilled没有走到 then方法里没有写状态为pending时要做什么 如果是pending时用两个数组将回调保存起来在resolve/reject调用时顺序遍历调用所有回调:

function MyPromise(executor) {
  let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  let promiseResult = null // 定义promise结果 初始为null
  // 定义存储then回调的数组
  const onFulfilledCallbacks = []
  const onRejectedCallbacks = []
  // 定义promise成功的resolve方法
  function resolve(result) {
    console.log('resolve执行了')
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.FULFILLED
      promiseResult = result
      onFulfilledCallbacks.forEach((fn) => fn(result))
    }
  }
  // 定义promise失败的reject方法
  function reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.REJECT
      promiseResult = reason
      onRejectedCallbacks.forEach((fn) => fn(reason))
    }
  }
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 参数校验
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }
    // 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
    if (promiseState === PromiseState.PENDING) {
      onFulfilledCallbacks.push(onFulfilled)
      onRejectedCallbacks.push(onRejected)
    }
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      queueMicrotask(() => {
        onFulfilled(promiseResult)
      })
    }
    if (promiseState === PromiseState.REJECT) {
      queueMicrotask(() => {
        onRejected(promiseResult)
      })
    }
  }
  // 如果executor执行报错则catch底层错误直接走reject
  try {
    // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
    executor && executor(resolve.bind(this), reject.bind(this))
  } catch (error) {
    reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
  }
}
console.log(1)
const promise = new MyPromise((res, rej) => {
  console.log(2)
  setTimeout(() => {
    res(3)
  })
})
console.log(4)
promise.then((res) => {
  console.log(res)
})
console.log(5)

 resolve(3)成功输出 回顾PromiseA+的调用时机 onFulfilled和onRejected要异步执行 所以还得改一下 保存回调时得包裹进微任务事件队列里保证其调用时是异步执行的:

function MyPromise(executor) {
  let promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  let promiseResult = null // 定义promise结果 初始为null
  // 定义存储then回调的数组
  const onFulfilledCallbacks = []
  const onRejectedCallbacks = []
  // 定义promise成功的resolve方法
  function resolve(result) {
    console.log('resolve执行了')
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.FULFILLED
      promiseResult = result
      onFulfilledCallbacks.forEach((fn) => fn(result))
    }
  }
  // 定义promise失败的reject方法
  function reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (promiseState === PromiseState.PENDING) {
      promiseState = PromiseState.REJECT
      promiseResult = reason
      onRejectedCallbacks.forEach((fn) => fn())
    }
  }
  // then方法
  this.then = function (onFulfilled, onRejected) {
    // 参数校验
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    onRejected =
      typeof onRejected === 'function'
        ? onRejected
        : (reason) => {
            throw reason
          }
    // 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
    if (promiseState === PromiseState.PENDING) {
      onFulfilledCallbacks.push(() => {
        queueMicrotask(() => {
          onFulfilled(promiseResult)
        })
      })
      onRejectedCallbacks.push(() => {
        queueMicrotask(() => {
          onRejected(promiseResult)
        })
      })
    }
    // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
    if (promiseState === PromiseState.FULFILLED) {
      queueMicrotask(() => {
        onFulfilled(promiseResult)
      })
    }
    if (promiseState === PromiseState.REJECT) {
      queueMicrotask(() => {
        onRejected(promiseResult)
      })
    }
  }
  // 如果executor执行报错则catch底层错误直接走reject
  try {
    // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
    executor && executor(resolve.bind(this), reject.bind(this))
  } catch (error) {
    reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
  }
}

 测试多次调用then:

const promise = new MyPromise((res, rej) => {
  setTimeout(() => {
    res(3)
  })
})
promise.then((res) => {
  console.log('then1:', res)
})
promise.then((res) => {
  console.log('then2:', res)
})

then回调顺序执行成功,最后实现then方法的链式调用 在then方法中返回一个新创建的Promise实例对象,将之前的then代码放入新创建的Promise的executor中执行 根据PromiseA+规范对onFulfilled/onRejected函数返回值进行解析成一个非promise对象的纯净状态存储,PromiseA+规范对then链式调用和Promise解决过程(解析返回值成非Promise对象的纯净状态的过程)的描述:

PromiseA+ 滚动到Then方法那一栏查看

实现最终完整代码:

const PromiseState = {
  PENDING: 'pending', // 等待态
  FULFILLED: 'fulfilled', // 完成态
  REJECT: 'reject', // 拒绝态
}

class MyPromise {
  promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  promiseResult = null // 定义promise结果 初始为null
  // 定义存储then回调的数组
  onFulfilledCallbacks = []
  onRejectedCallbacks = []
  constructor(executor) {
    // 如果executor执行报错则catch底层错误直接走reject
    try {
      // executor是个函数 执行创建promise时new Promise(executor)传入的executor 将resolve方法和reject方法传入
      executor && executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
    }
  }
  // 定义promise成功的resolve方法
  resolve(result) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (this.promiseState === PromiseState.PENDING) {
      this.promiseState = PromiseState.FULFILLED
      this.promiseResult = result
      this.onFulfilledCallbacks.forEach((fn) => fn(result))
    }
  }
  // 定义promise失败的reject方法
  reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (this.promiseState === PromiseState.PENDING) {
      this.promiseState = PromiseState.REJECT
      this.promiseResult = reason
      this.onRejectedCallbacks.forEach((fn) => fn(reason))
      console.error('Promise RejectError:', reason) // Promise执行异常打印 避免异常如果没有写reject回调什么都不会输出没有感知
    }
  }
  /**
   * @description promise解决过程 针对resolve()和reject()的返回值情况进行解析 拿到非promise的值 是promise就递归解析提取纯净状态(Promise的结果) PromiseA+中的以x为参数执行/拒绝Promise意思就是调用resolve/reject传入x
   * @param {*} promise promise1.then返回的promise2对象
   * @param {*} x promise1.then中onFulfilled/onRejected返回值
   * @param {*} resolve promise2的resolve方法
   * @param {*} reject promise2的reject方法
   */
  resolvePromise(promise2, x, resolve, reject) {
    /**
     * promise2不能和x相等 避免循环引用
     */
    if (promise2 === x) {
      throw new TypeError('promise2不能和onFulfilled/onRejected值完全相等!')
    }
    if (x instanceof MyPromise) {
      /**
       *  如果 x 为 Promise ,解析x的状态继续递归解析
       */
      x.then((y) => {
        this.resolvePromise(promise2, y, resolve, reject)
      }, reject)
    } else if (
      /**
       * 如果x为对象/函数 查找x是否有then方法并尝试执行(判断有then方法看是否为类Promise对象 是就要解析 调用then拿到状态继续递归解析直到状态不是一个带then方法的类Promise对象为止) 如果访问x.then方法抛出了异常则reject并将error当拒因返回
       * 如果有x.then方法则尝试调用 将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 this.resolvePromise ,第二个参数叫做 rejectPromise
       */
      x !== null &&
      (typeof x === 'function' || typeof x === 'object')
    ) {
      let then = null
      try {
        then = x.then
      } catch (error) {
        reject(error)
      }
      if (typeof then === 'function') {
        /**
         * called: resolvePromise和rejectPromise是否被调用的标记 避免多次调用
         * 如果 this.resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
         */
        let called = false
        try {
          then.call(
            x,
            (y) => {
              if (called) return
              called = true
              // 如果 this.resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
              this.resolvePromise(promise2, y, resolve, reject)
            },
            (r) => {
              if (called) return
              called = true
              // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
              reject(r)
            }
          )
        } catch (error) {
          if (called) {
            return
          }
          called = true
          /**
             如果调用 then 方法抛出了异常 error:
             如果 this.resolvePromise 或 rejectPromise 已经被调用(called=true),则忽略之否则以 error 为据因拒绝 promise
          */
          reject(error)
        }
      } else {
        // 如果 then 不是函数,以 x 为参数执行 promise
        resolve(x)
      }
    } else {
      // 如果 then 不是函数/对象,以 x 为参数执行 promise
      resolve(x)
    }
  }
  // then方法
  then(onFulfilled, onRejected) {
    const self = this
    // 参数校验在返回的promise里做了 可以注释掉了
    // onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    // onRejected =
    //   typeof onRejected === 'function'
    //     ? onRejected
    //     : (reason) => {
    //         throw reason
    //       }
    // 创建下一个调用的promise对象返回 实现链式调用
    const promise2 = new MyPromise((resolve, reject) => {
      // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
      if (this.promiseState === PromiseState.FULFILLED) {
        queueMicrotask(() => {
          try {
            // 如果不是函数则成功执行Promise(调resolve)原样返回想通的值
            if (typeof onFulfilled !== 'function') {
              resolve(this.promiseResult)
            } else {
              // 如果是函数则调用 并解析x
              const x = onFulfilled(this.promiseResult)
              this.resolvePromise(promise2, x, resolve, reject)
            }
          } catch (error) {
            // 如果执行异常则拒绝执行Promise并返回相同的拒因error
            reject(error)
          }
        })
      }
      if (this.promiseState === PromiseState.REJECT) {
        queueMicrotask(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.promiseResult)
            } else {
              const x = onRejected(this.promiseResult)
              this.resolvePromise(promise2, x, resolve, reject)
            }
          } catch (error) {
            reject(error)
          }
        })
      }
      // 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
      if (this.promiseState === PromiseState.PENDING) {
        this.onFulfilledCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              if (typeof onFulfilled !== 'function') {
                resolve(this.promiseResult)
              } else {
                const x = onFulfilled(this.promiseResult)
                this.resolvePromise(promise2, x, resolve, reject)
              }
            } catch (error) {
              reject(error)
            }
          })
        })
        this.onRejectedCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              if (typeof onRejected !== 'function') {
                reject(this.promiseResult)
              } else {
                const x = onRejected(this.promiseResult)
                this.resolvePromise(promise2, x, resolve, reject)
              }
            } catch (error) {
              reject(error)
            }
          })
        })
      }
    })
    return promise2
  }
}
const promise = new MyPromise((res, rej) => {
  res(3)
})
  .then((res) => {
    console.log('then1:', res)
    return res + 2
  })
  .then((res) => {
    console.log('then2:', res)
    return res + 3
  })
  .then((res) => {
    console.log('then3:', res)
  })

控制台链式打印:

then链式调用成功! 

最后附上promise六个静态方法的完整版代码:

const PromiseState = {
  PENDING: 'pending', // 等待态
  FULFILLED: 'fulfilled', // 完成态
  REJECT: 'reject', // 拒绝态
}

class MyPromise {
  promiseState = PromiseState.PENDING // 定义状态变 初始为pending等待态
  promiseResult = null // 定义promise结果 初始为null
  // 定义存储then回调的数组
  onFulfilledCallbacks = []
  onRejectedCallbacks = []
  constructor(executor) {
    // 如果executor执行报错则catch底层错误直接走reject
    try {
      // executor是个函数 执行创建promise时new MyPromise(executor)传入的executor 将resolve方法和reject方法传入
      executor && executor(this.resolve.bind(this), this.reject.bind(this))
    } catch (error) {
      this.reject(error) // 这里不需要绑定this 因为本身在MyPromise中执行 执行时上下文并未发生改变 不会产生this丢失
    }
  }
  // 定义promise成功的resolve方法
  resolve(result) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (this.promiseState === PromiseState.PENDING) {
      this.promiseState = PromiseState.FULFILLED
      this.promiseResult = result
      this.onFulfilledCallbacks.forEach((fn) => fn(result))
    }
  }
  // 定义promise失败的reject方法
  reject(reason) {
    // 如果当前是等待态 则扭转状态 修改promise结果
    if (this.promiseState === PromiseState.PENDING) {
      this.promiseState = PromiseState.REJECT
      this.promiseResult = reason
      this.onRejectedCallbacks.forEach((fn) => fn(reason))
      console.error('MyPromise RejectError:', reason) // Promise执行异常打印 避免异常如果没有写reject回调什么都不会输出没有感知
    }
  }
  /**
   * @description promise解决过程 针对resolve()和reject()的返回值情况进行解析 拿到非promise的值 是promise就递归解析提取纯净状态(Promise的结果) PromiseA+中的以x为参数执行/拒绝Promise意思就是调用resolve/reject传入x
   * @param {*} promise promise1.then返回的promise2对象
   * @param {*} x promise1.then中onFulfilled/onRejected返回值
   * @param {*} resolve promise2的resolve方法
   * @param {*} reject promise2的reject方法
   */
  resolvePromise(promise2, x, resolve, reject) {
    /**
     * promise2不能和x相等 避免循环引用
     */
    if (promise2 === x) {
      throw new TypeError('promise2不能和onFulfilled/onRejected值完全相等!')
    }
    if (x instanceof MyPromise) {
      /**
       *  如果 x 为 MyPromise ,解析x的状态继续递归解析
       */
      x.then((y) => {
        this.resolvePromise(promise2, y, resolve, reject)
      }, reject)
    } else if (
      /**
       * 如果x为对象/函数 查找x是否有then方法并尝试执行(判断有then方法看是否为类Promise对象 是就要解析 调用then拿到状态继续递归解析直到状态不是一个带then方法的类Promise对象为止) 如果访问x.then方法抛出了异常则reject并将error当拒因返回
       * 如果有x.then方法则尝试调用 将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 this.resolvePromise ,第二个参数叫做 rejectPromise
       */
      x !== null &&
      (typeof x === 'function' || typeof x === 'object')
    ) {
      let then = null
      try {
        then = x.then
      } catch (error) {
        reject(error)
      }
      if (typeof then === 'function') {
        /**
         * called: resolvePromise和rejectPromise是否被调用的标记 避免多次调用
         * 如果 this.resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
         */
        let called = false
        try {
          then.call(
            x,
            (y) => {
              if (called) return
              called = true
              // 如果 this.resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
              this.resolvePromise(promise2, y, resolve, reject)
            },
            (r) => {
              if (called) return
              called = true
              // 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
              reject(r)
            }
          )
        } catch (error) {
          if (called) {
            return
          }
          called = true
          /**
             如果调用 then 方法抛出了异常 error:
             如果 this.resolvePromise 或 rejectPromise 已经被调用(called=true),则忽略之否则以 error 为据因拒绝 promise
          */
          reject(error)
        }
      } else {
        // 如果 then 不是函数,以 x 为参数执行 promise
        resolve(x)
      }
    } else {
      // 如果 then 不是函数/对象,以 x 为参数执行 promise
      resolve(x)
    }
  }
  // then方法
  then(onFulfilled, onRejected) {
    const self = this
    // 参数校验在返回的promise里做了 可以注释掉了
    // onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (v) => v
    // onRejected =
    //   typeof onRejected === 'function'
    //     ? onRejected
    //     : (reason) => {
    //         throw reason
    //       }
    // 创建下一个调用的promise对象返回 实现链式调用
    const promise2 = new MyPromise((resolve, reject) => {
      // 根据对应状态执行对应回调 根据PromiseA+规范状态是不可逆的 所以只能执行其中一个
      if (this.promiseState === PromiseState.FULFILLED) {
        queueMicrotask(() => {
          try {
            // 如果不是函数则成功执行Promise(调resolve)原样返回想通的值
            if (typeof onFulfilled !== 'function') {
              resolve(this.promiseResult)
            } else {
              // 如果是函数则调用 并解析x
              const x = onFulfilled(this.promiseResult)
              this.resolvePromise(promise2, x, resolve, reject)
            }
          } catch (error) {
            // 如果执行异常则拒绝执行Promise并返回相同的拒因error
            reject(error)
          }
        })
      }
      if (this.promiseState === PromiseState.REJECT) {
        queueMicrotask(() => {
          try {
            if (typeof onRejected !== 'function') {
              reject(this.promiseResult)
            } else {
              const x = onRejected(this.promiseResult)
              this.resolvePromise(promise2, x, resolve, reject)
            }
          } catch (error) {
            reject(error)
          }
        })
      }
      // 如果是pending时保存回调解决异步执行resolve时then方法里的状态为pending导致不执行resolve/reject 在resolve/reject遍历保存的回调
      if (this.promiseState === PromiseState.PENDING) {
        this.onFulfilledCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              if (typeof onFulfilled !== 'function') {
                resolve(this.promiseResult)
              } else {
                const x = onFulfilled(this.promiseResult)
                this.resolvePromise(promise2, x, resolve, reject)
              }
            } catch (error) {
              reject(error)
            }
          })
        })
        this.onRejectedCallbacks.push(() => {
          queueMicrotask(() => {
            try {
              if (typeof onRejected !== 'function') {
                reject(this.promiseResult)
              } else {
                const x = onRejected(this.promiseResult)
                this.resolvePromise(promise2, x, resolve, reject)
              }
            } catch (error) {
              reject(error)
            }
          })
        })
      }
    })
    return promise2
  }
  // catch方法内部本质调的就是this.then(null, onRejected)
  catch(onRejected) {
    return this.then(null, onRejected)
  }
  // finally方法会在promise执行结束后必然执行 替代了一些一些收尾工作 以前需要resolve和reject里都写一遍callback逻辑 es2018出了finally方法解决这个问题
  finally(callback) {
    return this.then(callback, callback)
  }
  /**
   * @description 接收一个值转为Promise对象
   * @param  value 要转为Promise对象的值
   * @returns
   */
  static resolve(value) {
    // 如果是个Promise对象 则直接返回
    if (value instanceof MyPromise) {
      return value
    }
    // 如果是个thenable对象(包含then方法的对象) 则用resolve和reject去接管thenable的resolve和reject
    /**
   * MyPromise.resolve({
    then: function (resolve) {
      resolve('111') // thenable的resolve就是MyPromise的resolve接管的
    },
  }).then((r) => {
    console.log(r) // 111
  })
   */
    if (value instanceof Object && 'then' in value) {
      return new MyPromise((resolve, reject) => {
        value.then(resolve, reject)
      })
    }
    // 如果不是个Promise则以value为值返回一个Promise
    return new MyPromise((resolve) => {
      resolve(value)
    })
  }
  /**
   * @description 接收一个拒因返回一个带有拒因的promise对象
   * @param  value 要转为Promise对象的值
   * @returns
   */
  static reject(reason) {
    return new MyPromise((_, reject) => {
      reject(reason)
    })
  }
  /**
   * @description 并发执行promise 当所有promise都返回结果后完成promise 有一个拒绝promise则直接拒绝 不管其他有没有完成
   * @params promises 可迭代的promise集合
   */
  static all(promises) {
    return new MyPromise((resolve, reject) => {
      // 判断是否可迭代 不可迭代就reject
      if (!Array.isArray(promises)) {
        return reject(new Error('参数不可迭代!'))
      } else {
        const results = [] // 存储所有结果
        let executeCount = 0 // 存储执行个数
        promises.forEach((item, idx) => {
          /**
           * 用MyPromise.resolve将参数转promise对象统一调then处理 其内部判断了thenable对象和是否为promise对象 这里不用再判断thenable对象和promise对象的转换处理
           */
          MyPromise.resolve(item).then(
            (res) => {
              executeCount++
              // 将每一个结果顺序存储
              results[idx] = res
              // 执行完所有调resolve完成promise并返回所有结果的data数组
              executeCount === promises.length && resolve(results)
            },
            (reason) => {
              // 有一个失败就拒绝promise并返回拒因 不管其他promise是否完成
              reject(reason)
            }
          )
        })
      }
    })
  }
  /**
   * @description 所有promise都resolve/reject时完成promise
   * 和MyPromise.all的区别:
   * 1.有reject不会拒绝promise 不管resolve还是reject都会执行
   * 2.promise之间不相互依赖 reject不会打断其他promise执行 如果promise之间相互依赖则用all
   * @params promises 可迭代的promise集合
   */
  static allSettled(promises) {
    return new MyPromise((resolve, reject) => {
      // 判断是否可迭代
      if (!Array.isArray(promises)) {
        throw new TypeError('参数不可迭代')
      }
      if (promises.length === 0) {
        // 如果空数组则直接返回空数组
        return resolve(promises)
      }
      const results = []
      let executeCount = 0
      promises.forEach((item, idx) => {
        /**
         * 原生allSettled将非promise值内部转换成了promise包装 这里也用MyPromise.resolve包装
         * 用MyPromise.resolve接收参数转为一个promise对象 其内部判断了thenable对象和是否为promise对象 这里不用再判断thenable对象和promise对象的转换处理
         */
        MyPromise.resolve(item).then(
          (value) => {
            executeCount++
            // 每一项都构造一个当前promise状态和值的对象
            results[idx] = {
              status: PromiseState.FULFILLED,
              value,
            }
            // 所有promise执行完就resolve
            executeCount === promises.length && resolve(results)
          },
          (reason) => {
            executeCount++
            results[idx] = {
              status: PromiseState.REJECT,
              reason,
            }
            executeCount === promises.length && resolve(results)
          }
        )
      })
    })
  }
  /**
   * @description 传入一个可迭代的promise集合 只要有一个promise完成/全部失败就返回一个成功的/失败的状态
   */
  static any(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject(new Error('参数不可迭代'))
      }
      if (promises.length === 0) {
        return reject(new Error('传入的数组不能为空'))
      }
      const errors = [] // 存储拒因
      let executeCount = 0
      promises.forEach((item, idx) => {
        MyPromise.resolve(item).then(
          (value) => {
            /**
             * 只要有一个成功就直接resolve
             */
            return resolve(value)
          },
          (reason) => {
            executeCount++
            errors.push(reason)
            /**
             * 所有promise执行完将所有的拒因返回
             */
            executeCount === promises.length && reject(errors)
          }
        )
      })
    })
  }
  /**
   * @description 返回第一个完成/拒绝的promise
   */
  static race(promises) {
    return new MyPromise((resolve, reject) => {
      if (!Array.isArray(promises)) {
        return reject('参数不可迭代')
      }
      if (promises.length === 0) {
        return reject('数组不能为空')
      }
      promises.forEach((item) => {
        /**
         * 用MyPromise.resolve包装每一个参数 MyPromise.resolve方法内部对非promise和类thenable对象进行了判断处理 统一转promise处理
         * 用返回的promise的resolve和reject去接管每一个promise 返回第一个完成不管是成功/拒绝的promise
         **/
        MyPromise.resolve(item).then(resolve, reject)
      })
    })
  }
}
function testChainingThen() {
  const promise = new MyPromise((res, rej) => {
    res(3)
  })
    .then((res) => {
      console.log('then1:', res) // 3
      return res + 2
    })
    .then((res) => {
      console.log('then2:', res) // 5
      return res + 3
    })
    .then((res) => {
      console.log('then3:', res) // 8
    })
}
function testResolve() {
  // value为一个thenable对象时
  MyPromise.resolve({
    then: function (resolve) {
      resolve(111)
    },
  }).then((r) => {
    console.log(r) // 111
  })
  // value不为promise时
  MyPromise.resolve(11).then((res) => {
    console.log(res) // 11
  })
  // value为promise对象时
  MyPromise.resolve(new MyPromise((resolve) => resolve(1))).then((res) => {
    console.log(res) // 1
  })
}
function testReject() {
  MyPromise.reject('拒因').then(null, (reason) => {
    console.log(reason) // 拒因
  })
}
function testCatch(reason) {
  new MyPromise((_, reject) => {
    reject('报错测试catch')
  }).catch((reason) => {
    console.log(reason)
  })
}
function testFinally() {
  new MyPromise((resolve) => {
    resolve('resolve finally')
  })
    .then((res) => {
      console.log('res->', res)
    })
    .catch((error) => {
      console.log('catch->', error)
    })
    .finally(() => {
      console.log('finally callback执行')
    })
}
function testAll() {
  // 返回成功🌰
  const promise1 = MyPromise.resolve(3)
  const promise2 = {
    then: (res) => res(42),
  }
  const promise3 = new MyPromise((resolve, reject) => {
    setTimeout(resolve, 100, 'foo')
  })
  MyPromise.all([promise1, promise2, promise3]).then((values) => {
    console.log(values) // [3, 42, 'foo']
  })
  // 返回失败🌰
  // var p1 = new MyPromise((resolve, reject) => {
  //   setTimeout(resolve, 1000, 'one')
  // })
  // var p2 = new MyPromise((resolve, reject) => {
  //   setTimeout(resolve, 2000, 'two')
  // })
  // var p3 = new MyPromise((resolve, reject) => {
  //   setTimeout(resolve, 3000, 'three')
  // })
  // var p4 = new MyPromise((resolve, reject) => {
  //   setTimeout(resolve, 4000, 'four')
  // })
  // var p5 = new MyPromise((resolve, reject) => {
  //   reject('reject')
  // })
  // MyPromise.all([p1, p2, p3, p4, p5]).then(
  //   (values) => {
  //     console.log(values)
  //   },
  //   (reason) => {
  //     console.log(reason) // reject
  //   }
  // )
}
function testAllSettled() {
  const promise1 = MyPromise.resolve(3)
  const promise2 = 1
  const promises = [promise1, promise2]

  MyPromise.allSettled(promises).then((results) =>
    /**
     * {status: 'fulfilled', value: 3}
     * {status: 'fulfilled', value: 1}
     */
    results.forEach((result) => console.log(result))
  )
  setTimeout(() => {
    const p1 = MyPromise.resolve(3)
    const p2 = new MyPromise((resolve, reject) =>
      setTimeout(reject, 100, 'foo')
    )
    const ps = [p1, p2]

    MyPromise.allSettled(ps).then((results) =>
      /**
       * {status: 'fulfilled', value: 3}
       * {status: 'reject', reason: 'foo'}
       */
      results.forEach((result) => console.log(result))
    )
  }, 1000)
}
function testAny() {
  MyPromise.any([1, MyPromise.reject(2)]).then(
    (res) => {
      console.log(res)
    },
    (rej) => {
      console.log(rej)
    }
  )
}
function testRace() {
  const p1 = new MyPromise((resolve, reject) => setTimeout(resolve, 3000, 1))
  const p2 = new MyPromise((resolve, reject) => setTimeout(resolve, 2000, 2))
  const p3 = new MyPromise((resolve, reject) => setTimeout(resolve, 1000, 3))
  MyPromise.race([p1, p2, p3]).then(
    (value) => {
      console.log(value) // 3
    },
    (reason) => {
      console.log(reason)
    }
  )
}
// testChainingThen()
// testReject()
// testResolve()
// testCatch()
// testFinally()
// testAll()
// testAllSettled()
// testAny()
// testRace()

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值