JS之手写Promise

2021-02-01 11:15

阅读:547

  1. 准备

    (1)status 记录Promise的状态,初始值为pendding状态就是正在进行。

    (2)data 记录Promise返回的数据。

    (3)callbacks ,这是一个数组,用来记录需要执行的回调函数队列,里面存储了成功和失败的回调。

    (4) Promise的参数为一个函数(构造器),函数里面又有两个函数调用,好了,了解清楚之后我们就可以开始写Promise的结构了。

    向外暴露Promise:

    ;(function (window) {
        function Promise(executor){}
        window.Promise = Promise
    })(window)
    
  2. 构造器部分

    既然构造器中有两个可执行函数,那么我们就要实现这两个函数。其实两个函数都是差不多的结构只是状态不同,执行的回调函数不同。那么实现我们上边说了,需要有三种状态,那么我们就需要进行定义,而且还需要定义执行的回调函数队列,并且需要有一个变量来存储存储返回的数据,那么思路捋清楚了就可以开始了:

    /**
       * @param {Function} executor 执行器
       * @return {Promise} A new instance of Promise
       * when catch error set promise.status to rejected
       */
    function Promise(executor) {
        const self = this
    
        self.status = PENDING
        self.data = null
        self.callbacks = []
    
        function resolve(value) {
          // 状态只能改变一次
          if (self.status !== PENDING) {
            return
          }
    
          self.status = RESOLVED
          self.data = value
          if (self.callbacks.length > 0) {
            setTimeout(() => {
              self.callbacks.forEach((callbacksObj) => {
                callbacksObj.onResolved(value)
              })
            })
          }
        }
        function reject(reason) {
          if (self.status !== PENDING) {
            return
          }
          self.data = reason
          self.status = REJECTED
          if (self.callbacks.length > 0) {
            setTimeout(() => {
              self.callbacks.forEach((callbacksObj) => {
                callbacksObj.onRejected(reason)
              })
            })
          }
        }
        try {
          executor(resolve, reject)
        } catch (error) {
          reject(error)
        }
      }
    
  3. then方法实现:

    3.1

    then方法中也有两个回调函数,一个成功的回调,一个失败的回调,并且需要返回一个新的Promise,这就是为什么Promise可以链式调用的原因。写之前先捋一下逻辑,首先需要判断传入的是否为回调函数,如果为回调那么执行回调,如果成功回调为基本类型的值,那么次promise就直接变为成功状态,若为失败那么直接向下抛出异常值。

    then(onResolved, onRejected) {
        onRejected = typeof === ‘function‘ ? onRejected : value => value // 否则拿到value值构造一个函数赋值给成功参数
        onRejected = typeof === ‘function‘ ? onRejected : reason => { throw reason } // 否则变为一个向下抛出错误的异常函数
        const self = this // 老样子保存引用
        return new Promise((resolve, reject) => {
            if(self.status === PENDING) { // pending状态我们将回调推入回调函数队列
                self.callbacks.push({
                    OnResolved(value){}, // 回调里的操作决定了Promise的状态,所以还需要进行验证
                    onRejected(reason){}
                })       
            }
        } )
    }
    

    3.2

    then方法第二部分(解决回调函数内容)

    /* 
            返回promise的结果由onResolved/onRejected执行结果决定
            1. 抛出异常, 返回promise的结果为失败, reason为异常
            2. 返回的是promise, 返回promise的结果就是这个结果
            3. 返回的不是promise, 返回promise为成功, value就是返回值
            */
    

    所以我们需要一个 handler函数来帮助我们判断回调函数的处理结果,之后才执行相应处理。

    ?

    function handler(callback) {
            /* 
            返回promise的结果由onResolved/onRejected执行结果决定
            1. 抛出异常, 返回promise的结果为失败, reason为异常
            2. 返回的是promise, 返回promise的结果就是这个结果
            3. 返回的不是promise, 返回promise为成功, value就是返回值
            */
            try {
              const result = callback(self.data)
              if (result instanceof Promise) {
                result.then(resolve, reject)
              } else {
                resolve(result)
              }
            } catch (error) {
              reject(error)
            }
          }
    

    3.3

    then方法第三部分(完善then)

    Promise.prototype.then = function (onResolved, onRejected) {
        const self = this
        // 给参数赋予默认值,默认的函数
        onResolved =
          typeof onResolved === ‘function‘ ? onResolved : (value) => value
        onRejected =
          typeof onRejected === ‘function‘
            ? onRejected
            : (reason) => {
                throw reason
              }
    
        // 返回一个 promise
        return new Promise((resolve, reject) => {
          // 定义 handler函数,处理回调函数(利用闭包)
          function handler(callback) {
            /* 
            返回promise的结果由onResolved/onRejected执行结果决定
            1. 抛出异常, 返回promise的结果为失败, reason为异常
            2. 返回的是promise, 返回promise的结果就是这个结果
            3. 返回的不是promise, 返回promise为成功, value就是返回值
            */
            try {
              const result = callback(self.data)
              if (result instanceof Promise) {
                result.then(resolve, reject)
              } else {
                resolve(result)
              }
            } catch (error) {
              reject(error)
            }
          }
    
          if (self.status === RESOLVED) {
            // status 为 resolved 加入异步回调队列
            setTimeout(() => {
              handler(onResolved)
            })
          } else if (self.status === REJECTED) {
            // status 为 rejected 加入异步回调队列
            setTimeout(() => {
              handler(onRejected)
            })
          } else {
            // status 为 pending  装入回调数组
            self.callbacks.push({
              onResolved() {
                // 改变状态
                handler(onResolved)
              },
              onRejected() {
                handler(onRejected)
              },
            })
          }
        })
      }
    
  4. catch方法

    catch方法比较简单就是捕获错误,那么我们就可以直接复用then方法。

    Promise.prototype.catch = function (onRejected) {
        return this.then(null, onRejected)
      }
    
  5. resolve方法

    返回一个 Promise对象,其实是一个语法糖

    Promise.resolve = function (value) {
        return new Promise((resolve, reject) => {
          if (value instanceof Promise) {
            value.then(resolve, reject)
          } else {
            resolve(value)
          }
        })
      }
    
  6. reject方法

    类似:

    Promise.reject = function (reason) {
        return new Promise((resolve, reject) => {
          reject(reason)
        })
      }
    
  7. allrace方法

    all方法接受一个数组,数组中的数据为Promise多个实例,也可以是基本类型的值,当数组中的多个Promise的状态全都成功时,这个返回值才是成功值,,否则失败。需要补充的是all方法的成功返回值的顺序与数组中实例顺序是对应的关系。

    race方法的参数也是一个数组,数组中也是一个个promise实例,但是这个方法返回的值并不是数组,而是哪个promise率先执行完毕,那么此promise的状态值就为这个promise的状态值,听起来可能有点绕哈,下面开始代码的实现:

    /**
       * @param {[Promise]} promises The Array of promise
       * @return {Promise} A new promise
       */
      Promise.all = function (promises) {
        const values = new Array(promises.length) // 保存结果
        let resolvedCount = 0 // 统计resolved的Promise个数
        return new Promise((resolve, reject) => {
          promises.forEach((p, index) => {
            Promise.resolve(p).then(
              (value) => {
                resolvedCount += 1
                values[index] = value
                if (resolvedCount === promises.length) {
                  resolve(values)
                }
              },
              (reason) => {
                reject(reason)
              }
            )
          })
        })
      }
      /**
       * @param {[Promise]} promises The Array of promise
       * @return {Promise} A new promise
       */
      Promise.race = function (promises) {
        return new Promise((resolve, reject) => {
          promises.forEach((p) => {
            Promise.resolve(p).then(
              (value) => {
                resolve(value)
              },
              (reason) => {
                reject(reason)
              }
            )
          })
        })
      }
    

    完整代码

    项目的完整代码


评论


亲,登录后才可以留言!