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

Promise 的基本流程如下图

Promise 实现原理
以上对 Promise 做了一个简单的概述,下边我们来实现一个自己的 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() 函数

首先来看下这段代码

    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)

首先根据上边的示例来写 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)
    }
    
  ...
  ...
}

上边我们说过改变 Promise 状态的两种方式是 pending => fulfilled 或者 pending => rejected, 并且状态一经改变完成,就不可逆
所以在 resolve 和 reject 函数中要先判断 PromiseState 如果不是初始状态 pending 的情况下直接 return 不继续向下执行.

2、完善 原型上的 then 方法

先看这段代码

    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)
    // })

我们都知道 实例对象的 then 方法中接受两个回调函数,第一个是成功的回调函数,第二个是失败的回调函数,下边我们来继续完善 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)
    })

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

下边完善 catch 方法, catch 方法的实现很简单,直接调用 then 方法,并且把 失败的 onRejected 回调函数传入即可

 ...
  // 添加 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.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 方法
  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)
        })
      }
    })
  }
}

上一篇:swoole使用 常用案例


下一篇:手写Promise