Promise 实现原理

前言

这篇文章主要是探究 Promise 的实现原理,对于使用方法,这里不做过多概述,如果还有对 Promise 使用方式不太了解的,可以先看 阮一峰老师的 Promise 教程

Promise 是什么,为什么会出现 Promise?

  1. 抽象表达:
    1. Promise 是一门新的技术(ES6规范)
    2. Promise 是js 中进行异步变成的新解决方案,在没有 Promise 之前,旧方案是单纯使用回调函数
  2. 具体表达:
    1. 从语法上来说: promise 是一个构造函数
    2. 从功能上来说:promise 对象用来封装一个异步操作并可以获取其成功/失败的结果值
  3. 作用:
    1. Promise 主要是用来解决回调地狱的问题,在没有Promise 之前,如果异步任务比较多,并且有相互依赖的作用,就只能使用回调函数的方式来处理,这样就会形成回调地狱,代码可读性和可维护性会很差。
    2. Promise 的 then 方法支持链式调用,很好的解决了之前使用回调函数的书写方式,使代码逻辑很有条理
    3. 但是Promise 也是有缺点的,首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

Promise 的状态改变

promise 有三种状态

  1. pending (初始状态,或者说是执行中的状态),
  2. resolved || fulfilled (已成功,下文中将使用 fulfilled 作为已成功的状态)
  3. rejected (已失败)
    状态的改变只有两种方式 pending => fulfilled 或者 pending => rejected, 并且状态一经改变完成,就不可逆。成功的结果数据一般称为 value 失败的结果数据一般称为 reason

Promise 的基本流程如下图

在这里插入图片描述
以上对 Promise 做了一个简单的概述,下边我们来实现一个自己的 Promise

Promise 手动实现

首先我们先看下 原生的 Promise 实例对象中都包含的内容:
在这里插入图片描述
在这里插入图片描述

通过打印看到实例对象的原型上 包含 catch、finally、then、和 constructor 构造函数
最下边还有两个双方括号包含的内置属性 PromiseState、对应的就是Pormise 的状态 pending/ fulfilled/rejected 。 PromiseResult 对应的就是执行完成后,成功或失败的结果,

下边我们根据上图的内容,和 Promise API 先搭建一下 Promise 的整体框架代码如下:

// 这里直接声明一个 Promise 类可以覆盖掉 原生 Promise
class Promise {
  constructor (executor) {
    // 添加初始属性
    this.PromiseState = 'pending'
    this.PromiseResult = null

    // 声明一个栈,用来存放then方法中的回调,onResolved, onRejected,之所以用栈,是因为
    // 同一个实例 可以同时制定多个 then 方法,也就会有多个回调
    this.callbacks = []

    // 保存实例对象 this
    const self = this

    // resolve 函数
    function resolve (data) {
    }

    // reject 函数
    function reject (data) {
    }

    // 执行器函数
    executor(resolve, reject)
  }
  // 添加 then 方法 === es5  Promise.prototype.then () {}  方法
  then (onResolved, onRejected) {
  }
  // 添加 catch 方法 === es5  Promise.prototype.catch () {}  方法
  catch (onRejected) {
  }
  // 添加 resolve 方法  === es5 Promise.resolve () {} 方法
  static resolve (value) {
  }

  // 添加 reject 方法  === es5 Promise.reject () {} 方法
  static reject (reason) {
  }

  // 添加 all 方法 === es5 Promise.all () {} 方法
  static all (promises) {
  }

  // 添加 race 方法  === es5 Promise.race () {} 方法
  static race (promises) {
  }
}

上边的代码中 static 关键字 static 是ES6 class 中的新语法,用来声明 类中的静态方法
上边的 constructor(executor) 中的 executor 参数是执行器函数作为参数,其实就是下边代码中实例化 Promise 对象中的函数中的 参数 (resolve, reject) => {} 这部分内容,这个函数参数中有两个函数,第一个习惯上叫做 resolve 是成功的状态下执行的函数, 第二个是 reject 是失败状态下执行的函数

    let p = new Promise((resolve, reject) => {
      resolve('Ok')
    })

接下来我们开始一步步的完善上边的 Promise 类

1、完善 constructor 中的 resolve() 和 reject() 函数

示例代码

  <script>
    let p = new Promise((resolve, reject) => {
      resolve('Ok')
      // reject('Error')
      // throw 'Error' // 这里抛出错误,错误信息 也会赋值给 PromiseResult 属性,对应的  PromiseState 状态变为 rejected
      // 使用定时器 来模拟异步操作,执行成功后调用 resolve, 失败调用 reject  
      // setTimeout(() => {
      //   // resolve('OK')
      //   reject('Error')
      // }, 1000)
    })
    console.log(p)
  </script>

首先根据上边的示例来写 constructor 中的 resolve() 和 reject()

// 直接覆盖掉 原生 promise
class Promise {
  constructor (executor) {
    // 添加初始属性
    this.PromiseState = 'pending'
    this.PromiseResult = null

    // 声明一个栈,用来存放then方法中的回调,onResolved, onRejected,之所以用栈,是因为
    // 同一个实例 可以同时制定多个 then 方法,也就会有多个回调
    this.callbacks = []

    // 保存实例对象 this
    const self = this

    // resolve 函数
    function resolve (data) {
      // 修改状态前,先判断
      if (self.PromiseState !== 'pending') return
      // 1.修改对象状态 (promiseSate)
      self.PromiseState = 'fulfilled' // resolved
      // 2.设置对象结果值 (promiseResult)
      self.PromiseResult = data
    }

    // reject 函数
    function reject (data) {
      // 修改状态前,先判断
      if (self.PromiseState !== 'pending') return
      // 1.修改对象状态 (promiseSate)
      self.PromiseState = 'rejected'
      // 2.设置对象结果值 (promiseResult)
      self.PromiseResult = data
    }
    
    // 执行器函数
    // 这里使用 try catch 是为了捕获执行器执行的时候抛出异常
    try {
      // 同步调用[执行器函数(也就是 executor)]
      executor(resolve, reject)
    } catch (e) {
      // 修改 Promise 对象状态为 失败
      reject(e)
    }
    
  ...
  ...
}

首先我们用:

  1. this.PromiseState = 'pending' 来管理状态,状态改变的时候直接修改这个变量的值 。
  2. this.PromiseResult = null 这个变量用来管理 执行完成后返回的结果值
  3. this.callbacks = [] 栈用来存放,当实例对象指定多个 then 方法时,传入的 onResolved onRejected 回调函数,后续会说明。
  1. 上边我们说过改变 Promise 状态的两种方式是 pending => fulfilled 或者 pending => rejected, 并且状态一经改变完成,就不可逆
  2. 所以在 resolve 和 reject 函数中要先判断 PromiseState 如果不是初始状态 pending 的情况下直接 return 不继续向下执行. 否则就是 pending 状态,对应的改变 PromiseState 状态为 fulfilled || rejected 和 PromiseResult 的值

2、完善 原型上的 then 方法

示例代码

  <script>
    let p = new Promise((resolve, reject) => {
      resolve('Ok')
      // reject('Error')

      // setTimeout(() => {
      //   // resolve('OK')
      //   reject('Error')
      // }, 1000)
    })

    p.then(value => {
      console.log(value) // Ok
    }, reason => {
      console.warn(reason) // 调用 reject 这里 reason 就是 Error
    })
    
    // 下边的注释打开以后,就等于是给 实例对象 p 指定了 多个 then 方法,这种情况下,多个 then 方法都会被执行
    // p.then(value => {
    //   alert(value)
    // }, reason => {
    //   alert(reason)
    // })
    
   <script>

then 方法特性:
接受两个回调函数:

  1. onResolved 函数: 成功的回调函数 (value) => {}
    PromiseState => fulfilled PromiseResult => 成功的返回值
  2. onRejected 函数: 失败的回调函数 (reason) => {}
    PromiseState => rejected PromiseResult => 失败的返回值
  3. 以上两个参数都是可选的,如果调用 then 方法的时候两个参数都不传,为了不影响then后续的链式调用,then方法内部需要自己再执行onResolved 和 onRejected函数 ,这样如果执行过程中抛出异常就会被 then 最后的 catch 方法捕捉到。onResolved 后,就不会影响后续的 then 方法的执行
  4. then 方法中会返回一个 Promise 对象,这样才可以开启 then 方法的链式调用,通过then的链式调用串连多个同步/异步任务
  5. 如果 then 方法中抛出一个异常 throw ‘Fail’ 错误信息 也会赋值给 PromiseResult 属性,对应的 PromiseState 状态变为 rejected
    抛出异常示例代码
    let p = new Promise((resolve, reject) => {
      resolve('Ok')
    })

    let res = p.then(value => {
      throw 'Fail'
    }, reason => {
      console.warn(reason)
    })
    console.log(res)

res 示例对象中的 PromiseResult = ‘Fail’ PromiseState = ‘rejected’

  1. 如果Promise 对象中封装了任务,然后在调用实例对象上的 then 方法的时候,这里会涉及到一个状态改变的时机问题,
    如果封装的是同步任务,则先改变状态,在执行 then 方法中的回调函数
    如果封装的是异步任务,则先执行 then 方法中的回调,然后把then 中的onResolved 和 onRejected 存起来 等异步任务执行完成以后在 修改 状态,再执行之前存储的 onResolved 或者 onRejected 示例如下
  <script>
    let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('OK')
      }, 1000)
    })
    p.then(value => {
      console.log(value)
    }, reason => {
      console.warn(reason)
    })
  </script>

完善 then 方法

...
...
  // 添加 then 方法
  then (onResolved, onRejected) {
    const self = this
    // 判断调用 then 方法的时候,回调函数参数 onRejected 没有传的情况,给 onRejected 指定一个函数,如果执行失败,就会走这个指定的
    // onRejected 函数,然后抛出错误,链式调用最后边的 catch 就会捕获到
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }
    // 判断如果调用 then 方法的时候什么都不传,并且后边还跟着 then 方法的情况,给 onResolved 指定一个函数执行,这样可以让后边的 then 不受影响继续向下执行
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    // 这里之所以需要 return Promise 是因为,then 方法调用也会有返回Promise对象
    // 返回的 Promise 对象中的 PromiseResult 的值取决于 传入进来的 onResolved 回调函数执行后的返回值
    // 返回的 Promise 对象中的 PromiseState 的值取决于:
    //    执行器中的回调函数是同步操作:PromiseState = 执行器中调用的回调函数 是 resolve(fulfilled) 还是 reject(rejected)
    // 
    return new Promise((resolve, reject) => {
      // 封装函数
      function callback(type) {
        // 这里的 try  catch 是为了防止实例对象调用 then 方法中的两个回调 onResolved, onRejected 函数中抛出错误的时候可以继续执行代码,并捕获错误信息
        try {
          // 获取回调函数的执行结果
          let result = type(self.PromiseResult)
          // 判断
          // 如果实例中调用 then 方法的返回值也是一个 Promise对象,这里的 result等于也就是一个 Promise 对象的实例
          // 然后继续调用实例上的 then 方法执行对应的 resolve() 和 reject 就可以,这样就会重新去执行 Promise 构造函数中的
          // resolve 或者 reject 方法
          if (result instanceof Promise) {
            // 如果是Promise 类型的对象
            result.then(v => {
              resolve(v)
            }, r => {
              reject(r)
            })
          } else {
            // 结果的对象状态为 [成功]
            resolve(result)
          }
        } catch (e) {
          reject(e)
        }
      }
      // 调用回调函数,先判断 PromiseState 状态
      // 这里是同步的状态下,已经修改过状态,并修改了结果以后,执行到 then 的操作
      // 所以要先判断状态
      if (this.PromiseState === 'fulfilled') {
        // 这里要用 setTimeout 包裹一下,使其变为异步任务,把任务放进队列
        setTimeout(() => {
          callback(onResolved) 
        })
      }
  
      if (this.PromiseState === 'rejected') {
        // 这里要用 setTimeout 包裹一下,使其变为异步任务,把任务放进队列
        setTimeout(() => {
          callback(onRejected)
        })
      }
  
      // 这里是异步执行的状态下,状态还是 pending 没有被修改过,说明异步执行还在执行过程中,
      // 然后先执行到了 then 方法。这里需要先把 onResolved, onRejected 两个回调函数先存一下
      // 等到异步执行完成,调用了 resolve || reject 的时候,在 resolve || reject 函数中再去判断
      // callback 对象中是否有存储回调函数,有的话在执行回调函数
      if (this.PromiseState === 'pending') {
        this.callbacks.push({
          onResolved: function () {
            callback(onResolved)
          },
          onRejected: function () {
            callback(onRejected)
          }
        })
      }
    })
  }
  ...
  ...

完善了 then 方法以后,还要对应的在继续完善下 constructor 中的 resolve reject 方法 ,因为上边的代码最后部分 我们可以看到 ,如果给实例对象 p 指定多个 then 方法的情况下,onResolved / onRejected回调函数会被 追加到 callbacks 栈中,在 constructor 中的 resolve reject 方法是 执行完成后调用的方法,这两个方法执行的最后也要对应的执行下 callbacks 栈中的回调函数
代码如下:

  constructor (executor) {
	...
	...
    // resolve 函数
    function resolve (data) {
      // 修改状态前,先判断
      if (self.PromiseState !== 'pending') return
      // 1.修改对象状态 (promiseSate)
      self.PromiseState = 'fulfilled' // resolved
      // 2.设置对象结果值 (promiseResult)
      self.PromiseResult = data
      // Promise实例中,异步执行完成,执行回调
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onResolved(data)
        })
      })
    }

    // reject 函数
    function reject (data) {
      // 修改状态前,先判断
      if (self.PromiseState !== 'pending') return
      // 1.修改对象状态 (promiseSate)
      self.PromiseState = 'rejected'
      // 2.设置对象结果值 (promiseResult)
      self.PromiseResult = data
      // Promise实例中,异步执行完成,执行回调
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onRejected(data)
        })
      })
    }
	...
	...
  }

上边的内容不是很好理解,最好是根据 then 方法的特性,写一下示例运行下代码比较好。

完善原型上的 catch 方法

代码示例

    let p = new Promise((resolve, reject) => {
      setTimeout(() => {
        // resolve('Ok')
        reject('Error')
      }, 1000);
    })

    p.then(value => {
      console.log(1111)
      // throw 'Errr'
    }).then(value => {
      console.log(2222)
    }).then(value => {
      console.log(3333)
    }).catch(reason => {
      console.warn(reason)
    })

catch 特性:

  1. 接受一个失败的回调函数,这个参数是必须传的。
  2. 异常穿透
  1. 上边的代码如果调用 resolve(‘Ok’) 下边then 方法上的执行顺序是从上到下依次执行的,如果调用的是 reject(‘Error’) 则上边的所有then 方法都不会执行,只执行最后的 catch 方法进行错误捕获。
  2. 如果第一个then 中的 throw ‘Error’ 抛出错误以后,下边的两个 then 方法也不会执行,只执行最后的 catch 方法
    这种特性叫做异常穿透,如果执行过程中任何一个环节出现错误,都会传到最后失败的回调中处理

下边完善 catch 方法, catch 方法的实现很简单,直接调用 then 方法,并且把 失败的 onRejected 回调函数传入即可, then 方法内部做了 try catch 的异常捕获,只要捕获到 异常,就会执行 rejecte(e) 方法,PromiseState=’rejected‘ PromiseResult=’异常信息‘

 ...
  // 添加 catch 方法
  catch (onRejected) {
    return this.then(undefined, onRejected)
  }
  ...

完善 Promise.resolve 方法

示例代码:

    // const p = Promise.resolve('OK')
    // console.log(p)

    // const p2 = Promise.resolve(new Promise((resolve, reject) => {
    //   // resolve('success')
    //   reject('error')
    // }))
    // console.log(p2)


    const p3 = Promise.resolve(Promise.resolve('Oh Yeah'))
    console.log(p3)

静态方法 resolve() 完善

...
  // 添加 resolve 方法
  static resolve (value) {
    // 返回 promise 对象
    return new Promise((resolve, reject) => {
      // 如果传入的 value 也是promise 实例, 则执行这个实例的 then 方法,然后执行对应的 resolve  reject 方法
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        // 如果不是 promise 对象,直接设置成功
        resolve(value)
      }
    })
  }
  ...

因为 Promise.resolve 方法执行完成后也会返回一个 Promise 对象,所以这个静态方法中也要返回一个实例化后的 Promise 对象

完善Promise.reject() 方法

示例代码:

  <script>
    const p = Promise.reject('Error')

    const p2 = Promise.reject(new Promise((resolve, reject) => {
      resolve('Ok')
    }))

    console.log(p)
    console.log(p2)
  </script>

完善静态方法 reject

  // 添加 reject 方法
  static reject (reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

因为 reject() 方法的作用就是执行失败的回调,并返回一个 Promise 对象,所以 reject 静态方法中直接返回 实例化的 Promise 对象,并调用这个对象的 reject 方法。把失败信息传入到 reject(reason)中

完善 Pomise.all() 方法

示例代码:

    // let p1 = new Promise((resolve, reject) => {
    //   setTimeout(() => {
    //     resolve('OK')
    //   }, 1000);
    // })

    // let p2 = Promise.resolve('SUccess')
    // let p3 = Promise.resolve('Oh Yeah')

    let p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('OK')
      }, 1000);
    })

    let p2 = Promise.reject('SUccess')
    let p3 = Promise.resolve('Oh Yeah')


    // 调用 all 方法
    // debugger
    let result = Promise.all([p1, p2, p3])
    console.log(result)

all() 方法的特性:

  1. all 方法中接受一个数组,数组中的每一项都是一个 Promise 对象,数组中的这些 Promise 对象全部都执行成功后的 resolve() 方法,才会最终成功,状态变为 fulfilled 返回值也是一个数组,数组中的每一项对应 all([ ]) 方法数组中每个 Promise 对象返回的结果值。如果其中只要有一个失败,就会全部失败,状态直接变为 rejected, 返回值也会变为失败返回的值。

完善 all 静态方法

  // 添加 all 方法
  static all (promises) {
    // 返回结果是 promise 对象
    return new Promise((resolve, reject) => {
      // 声明变量
      let count = 0
      let arr = []
      // 遍历
      for (let i = 0; i < promises.length; i++) {
        //
        promises[i].then(v => {
          // 得知对象的状态是成功 每个 promise 对象都成功
          count++
          // 将当前 promise 对象成功的结果,存入到数组中,这里最好不好使用 push 添加,这样顺序有可能会乱,要使用下标的方式添加
          arr[i] = v
          // 确保 all 中所有的 Promise 对象都执行成功了,再去改变 promiseState 状态,再赋值
          if (count === promises.length) {
            resolve(arr)
          }
        }, r => {
          reject(r)
        })
      }
    })
  }

上边有个很关键的部分,要确保所有的Promise 对象都执行成功以后,再去调用 resolve() 方法,resolve 方法中再修改 PromiseState 状态为 fulfilled

完善 Promise.race() 静态方法

示例代码:

  <script>

    let p1 = new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('OK')
      }, 0);
    })

    // let p2 = Promise.resolve('SUccess')
    let p2 = Promise.reject('Error')
    let p3 = Promise.resolve('Oh Yeah')


    // 调用 all 方法
    // debugger
    let result = Promise.race([p1, p2, p3])
    console.log(result)
  </script>

race() 方法特性:
race 翻译后是赛跑的意思,这个方法中也是接受一个数组作为参数,数组的每一项都是一个 promise 对象。这些对象中最先执行完成并且成功的返回值会作为 PromiseResult 的值,状态变为 fulfilled 。 如果其中有一个失败的,这个失败的对象的 返回值 会作为 PromiseResult 的值,状态变为 rejected

完善 race() 静态方法

  // 添加 race 方法
  static race (promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(v => {
          // 修改返回对象的状态为 [成功]
          resolve(v)
        }, r => {
          // 修改返回对象的状态为 [失败]
          reject(r)
        })
      }
    })
  }

至此 Promise 封装完成。完整代码如下

// 直接覆盖掉 原生 promise
class Promise {
  constructor (executor) {
    // 添加初始属性
    this.PromiseState = 'pending'
    this.PromiseResult = null

    // 声明一个栈,用来存放then方法中的回调,onResolved, onRejected,之所以用栈,是因为
    // 同一个实例 可以同时制定多个 then 方法,也就会有多个回调
    this.callbacks = []

    // 保存实例对象 this
    const self = this

    // resolve 函数
    function resolve (data) {
      // 修改状态前,先判断
      if (self.PromiseState !== 'pending') return
      // 1.修改对象状态 (promiseSate)
      self.PromiseState = 'fulfilled' // resolved
      // 2.设置对象结果值 (promiseResult)
      self.PromiseResult = data
      // Promise实例中,异步执行完成,执行回调
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onResolved(data)
        })
      })
    }

    // reject 函数
    function reject (data) {
      // 修改状态前,先判断
      if (self.PromiseState !== 'pending') return
      // 1.修改对象状态 (promiseSate)
      self.PromiseState = 'rejected'
      // 2.设置对象结果值 (promiseResult)
      self.PromiseResult = data
      // Promise实例中,异步执行完成,执行回调
      setTimeout(() => {
        self.callbacks.forEach(item => {
          item.onRejected(data)
        })
      })
    }

    // 这里使用 try catch 是为了捕获执行器执行的时候抛出异常
    try {
      // 同步调用[执行器函数(也就是 executor)]
      executor(resolve, reject)
    } catch (e) {
      // 修改 Promise 对象状态为 失败
      reject(e)
    }
  }
  // 添加 then 方法
  then (onResolved, onRejected) {
    const self = this
    // 判断调用 then 方法的时候,回调函数参数 onRejected 没有传的情况,给 onRejected 指定一个函数,如果执行失败,就会走这个指定的
    // onRejected 函数,然后抛出错误,链式调用最后边的 catch 就会捕获到
    if (typeof onRejected !== 'function') {
      onRejected = reason => {
        throw reason
      }
    }
    // 判断如果调用 then 方法的时候什么都不传,并且后边还跟着 then 方法的情况,给 onResolved 指定一个函数执行,这样可以让后边的 then 不受影响继续向下执行
    if (typeof onResolved !== 'function') {
      onResolved = value => value
    }
    // 这里之所以需要 return Promise 是因为,then 方法调用也会有返回Promise对象
    // 返回的 Promise 对象中的 PromiseResult 的值取决于 传入进来的 onResolved 回调函数执行后的返回值
    // 返回的 Promise 对象中的 PromiseState 的值取决于:
    //    执行器中的回调函数是同步操作:PromiseState = 执行器中调用的回调函数 是 resolve(fulfilled) 还是 reject(rejected)
    // 
    return new Promise((resolve, reject) => {
      // 封装函数
      function callback(type) {
        // 这里的 try  catch 是为了防止实例对象调用 then 方法中的两个回调 onResolved, onRejected 函数中抛出错误的时候可以继续执行代码,并捕获错误信息
        try {
          // 获取回调函数的执行结果
          let result = type(self.PromiseResult)
          // 判断
          // 如果实例中调用 then 方法的返回值也是一个 Promise对象,这里的 result等于也就是一个 Promise 对象的实例
          // 然后继续调用实例上的 then 方法执行对应的 resolve() 和 reject 就可以,这样就会重新去执行 Promise 构造函数中的
          // resolve 或者 reject 方法
          if (result instanceof Promise) {
            // 如果是Promise 类型的对象
            result.then(v => {
              resolve(v)
            }, r => {
              reject(r)
            })
          } else {
            // 结果的对象状态为 [成功]
            resolve(result)
          }
        } catch (e) {
          reject(e)
        }
      }
      // 调用回调函数,先判断 PromiseState 状态
      // 这里是同步的状态下,已经修改过状态,并修改了结果以后,执行到 then 的操作
      // 所以要先判断状态
      if (this.PromiseState === 'fulfilled') {
        // 这里要用 setTimeout 包裹一下,使其变为异步任务,把任务放进队列
        setTimeout(() => {
          callback(onResolved) 
        })
      }
  
      if (this.PromiseState === 'rejected') {
        // 这里要用 setTimeout 包裹一下,使其变为异步任务,把任务放进队列
        setTimeout(() => {
          callback(onRejected)
        })
      }
  
      // 这里是异步执行的状态下,状态还是 pending 没有被修改过,说明异步执行还在执行过程中,
      // 然后先执行到了 then 方法。这里需要先把 onResolved, onRejected 两个回调函数先存一下
      // 等到异步执行完成,调用了 resolve || reject 的时候,在 resolve || reject 函数中再去判断
      // callback 对象中是否有存储回调函数,有的话在执行回调函数
      if (this.PromiseState === 'pending') {
        this.callbacks.push({
          onResolved: function () {
            callback(onResolved)
          },
          onRejected: function () {
            callback(onRejected)
          }
        })
      }
    })
  }
  // 添加 catch 方法
  catch (onRejected) {
    return this.then(undefined, onRejected)
  }
  // 添加 resolve 方法
  static resolve (value) {
    // 返回 promise 对象
    return new Promise((resolve, reject) => {
      // 如果传入的 value 也是promise 实例, 则执行这个实例的 then 方法,然后执行对应的 resolve  reject 方法
      if (value instanceof Promise) {
        value.then(v => {
          resolve(v)
        }, r => {
          reject(r)
        })
      } else {
        // 如果不是 promise 对象,直接设置成功
        resolve(value)
      }
    })
  }

  // 添加 reject 方法
  static reject (reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  // 添加 all 方法
  static all (promises) {
    // 返回结果是 promise 对象
    return new Promise((resolve, reject) => {
      // 声明变量
      let count = 0
      let arr = []
      // 遍历
      for (let i = 0; i < promises.length; i++) {
        //
        promises[i].then(v => {
          // 得知对象的状态是成功 每个 promise 对象都成功
          count++
          // 将当前 promise 对象成功的结果,存入到数组中,这里最好不好使用 push 添加,这样顺序有可能会乱,要使用下标的方式添加
          arr[i] = v
          // 确保 all 中所有的 Promise 对象都执行成功了,再去改变 promiseState 状态,再赋值
          if (count === promises.length) {
            resolve(arr)
          }
        }, r => {
          reject(r)
        })
      }
    })
  }

  // 添加 race 方法
  static race (promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(v => {
          // 修改返回对象的状态为 [成功]
          resolve(v)
        }, r => {
          // 修改返回对象的状态为 [失败]
          reject(r)
        })
      }
    })
  }
}