手写Promise

手写一个Promise
采用ES5 IIFE格式

/**
 * 自定义myPromise函数模块
 * 
 * ES5  IIFE
 * 
 * Isaac_Jeeen 2021_09_27
 */

(function (Window) {
  const PEN = 'pending'
  const RES = 'resolved'
  const REJ = 'rejected'

  /**
   * 执行器函数
   * @param {function} executor 
   */
  function myPromise(executor) {
    const self = this
    // 状态 初始值为pending
    self.status = PEN
    // 用于存储结果数据的属性
    self.data = undefined
    // 保存.then中的回调
    // 数组中每个元素的结构{onResolved(){} , onRejected(){}}
    self.callback = []

    function resolve(value) {
      // 如果状态不是pending,就不能改
      if (self.status !== PEN) return
      // 改状态
      self.status = RES
      // 保存value
      self.data = value
      // 如果有回调,立即异步执行 onResolved函数
      if (self.callback.length > 0) {
        self.callback.forEach(callbackObj => {
          setTimeout(() => {
            callbackObj.onResolved(value)
          })
        });
      }
    }

    function reject(reason) {
      // 如果状态不是pending,就不能改
      if (self.status !== PEN) return
      // 改状态
      self.status = REJ
      // 保存value
      self.data = reason
      // 如果有回调,立即异步执行 onResolved函数
      if (self.callback.length > 0) {
        self.callback.forEach(callbackObj => {
          setTimeout(() => {
            callbackObj.onRejected(reason)
          })
        });
      }
    }

    try {
      executor(resolve, reject)
    }
    catch (error) {
      // 如果执行器抛出异常,myPromise变为失败状态
      reject(error)
    }
  }

  /**
   * myPromise对象的resolve()
   * 返回指定结果的成功的myPromise
   */
  myPromise.resolve = function (value) {
    // 返回一个新的myPromise对象,可以是成功的,也可以是失败的
    // 成功的情况
    // 1.1收到是是非myPromise
    // 1.2收到的是成功的myPromise
    // 失败的情况
    // 2.1收到一个失败的myPromise

    return new myPromise((resolve, reject) => {
      if (value instanceof myPromise) {
        // 接受的参数是myPromise
        // value是传进来的myPromise
        // 回调是return出去的新myPromise
        // 主要就是根据传进来的对象的状态,自适应更改return出去的新myPromise状态
        // 成功就resolve(),失败就reject(),参数都是上一个myPromise自动传进去的
        // 见.then()的实现
        value.then(resolve, reject)
      }
      else {
        // 接受参数非myPromise
        // 直接让这个返回的myPromise对象成功
        resolve(value)
      }
    })
  }

  /**
   * myPromise对象的reject()
   * 返回指定结果的失败的myPromise
   */
  myPromise.reject = function (reason) {
    // 只接受reason(失败的原因),参数不可以是一个新的myPromise对象
    // 返回一个新的只能是失败的myPromise对象
    // 将失败的原因传递下去
    return new myPromise((resolve, reject) => {
      // 因为要返回一个失败的myPromise对象
      // 让一个myPromise对象失败的途径就是调用它的reject()
      // 同时将失败的原因reason传递进去
      reject(reason)
    })

  }

  /**
   * myPromise对象的then()
   * 返回一个新的myPromise对象
   * @param {function} onResolved 成功的回调
   * @param {function} onRejected 失败的回调
   */
  myPromise.prototype.then = function (onResolved, onRejected) {
    const self = this
    // 指定回调函数的默认值(必须是函数)
    onResolved = typeof onResolved === 'function' ? onResolved : value => value
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }

    // 返回一个新的myPromise对象
    return new myPromise((resolve, reject) => {
      /**
       * 将重复的代码抽离、复用
       * @param {function} callback 
       */
      function handle(callback) {
        // 1.如果抛出异常,返回失败的myPromise reason是error
        // 2.如果回调函数return不是myPromise对象,那么返回成功的myPromise,value就是返回值
        // 3.如果回调return就是myPromise对象,那么返回的myPromise根据return的myPromise结果
        try {
          // 接收上一个myPromise的onResolved()【成功回调】返回的结果
          const res = callback(self.data)
          if (res instanceof myPromise) {
            // 3.如果回调return就是myPromise对象,那么返回的myPromise根据return的myPromise结果
            // 如果上一个回调返回的就是myPromise对象
            // 那返回的myPromise对象根据上一个的来

            // 这里的res就是上一个myPromise对象的成功回调返回的新myPromise【A】对象
            // 直接调用then来获得返回的【A】的状态,以便return出一个一样的myPromise【B】

            // --------------------
            res.then(
              // 注意!!
              // 这里的resolve和reject都是调用return 出来的这个B的
              // 因为要让B成功!!!
              // 让一个myPromise对象成功的方法就是调用它的resolve()
              // 前一个value是A(res)的成功的value  传过来的
              // 后一个value是传给B的!!因为要让B成功,所以调用它的resolve(),并传入A的value
              // reject同理,B按照A来
              value => resolve(value),
              reason => reject(reason)
            )
            // -----------------------

            // 等价于

            // -----------------------
            // res.then(resolve, reject)
            // ------------------------

            // 解释
            // 原来的value => resolve(value),
            // 就是一个函数,把A的value传给B的resolve()
            // 等价于直接用B的resolve当回调,且不要执行
            // 因为回调函数三原则(自定义的函数,自己没有调用,最终执行)

            /**
             * (1)
             *      function fun(){}
             *      div.onclick = event => {fun(event)}
             * 等价于
             * (2)
             *      div.onclick = func
             * 千万不要写成
             * div.onclick = func()
             * 这样的话就等于把func执行 return的结果给点击绑定了
             * 
             * 回调应该是一个函数(不管是上面的箭头还是普通函数)!!!而不是执行结果
             * 回调函数不用我们执行而是绑定的事物执行,回调函数三原则(自定义的函数,自己没有调用,最终执行)
             * 对于(1),回调函数是箭头函数,然后等它被执行完,结果还是是一个结果[fun(event)]
             * fun(event)的意思就是fun的执行结果,参数是绑定的点击事件的event
             * 
             * 对于(2),回调函数就是fun(没执行),等它被执行的时候形参就是绑定的点击事件的event
             */
          }
          else {
            // 2.如果回调函数return不是myPromise对象,那么返回成功的myPromise,value就是返回值
            // 如果上一个的回调函数return不是myPromise对象
            // 那么返回成功的myPromise,value就是返回值
            // 直接调用返回的myPromise对象的resolve
            // 把上一个myPromise对象的成功回调返回的结果传进去
            resolve(res)
          }
        }
        catch (error) {
          // 1.如果抛出异常,返回失败的myPromise reason是error
          // 因为要返回一个失败的myPromise,所以调用返回的myPromise的reject()
          // 因为要失败的信息,所以error传入当前myPromise的reject(error)
          reject(error)
        }
      }


      // 如果是先指定的回调,后修改状态
      // 那么status就是pengding,可以将成功失败回调函数收集起来
      // 等待resolve | reject修改完状态后再调用
      if (self.status === PEN) {
        self.callback.push({
          // 上一个myPromise状态还没确定呢
          // 所以调用一下上一个myPromise对象的onResolved和onRejected函数
          onResolved() {
            handle(onResolved)
          },
          onRejected() {
            handle(onRejected)
          }
        })
      }
      // 如果是修改完状态再指定回调函数
      // 且状态已经是成功的(resolved)
      else if (self.status === RES) {
        // .then中的两个回调函数本身需要异步执行
        setTimeout(() => {
          handle(onResolved)
        })
      }
      else {
        // self.status === rejected
        setTimeout(() => {
          handle(onRejected)
        })
      }
    })

  }

  /**
   * myPromise对象的catch()
   * 返回一个新的myPromise对象
   * @param {function} onRejected 只有失败的回调
   */
  myPromise.prototype.catch = function (onRejected) {
    return this.then(undefined, onRejected)
  }

  /**
   * myPromise对象的all()
   * 返回一个myPromise (只有当所有参数全部成功时才成功)
   * 
   */
  myPromise.all = function (myPromises) {
    // 返回一个myPromise对象,所有的都成功才会返回成功的myPromise对象,value为成功值的数组
    // 有一个失败就返回失败的myPromise,reason是失败的那个reason
    // 凡是跟形参myPromise状态有关的,步骤如下
    // 1、return new myPromise
    // 2、执行器函数里面执行形参相关的.then,因为.then就是能获得成功/失败的结果并返回一个新myPromise
    // 3、为了让return的新的myPromise状态与之相关,要调用return的这个myPromise的resolve/reject

    const values = new Array(myPromises.length)// 用来保存所有形参中成功的myPromise的数据
    let count = 0// 用来保存成功的myPromise数量
    return new myPromise((resolve, reject) => {
      // 遍历获取形参中所有myPromise的结果
      myPromises.forEach((p, index) => {
        myPromise.resolve(p).then(
          value => {
            values[index] = value
            count++
            if (count === myPromises.length) {
              resolve(values)
            }
          },
          reason => {
            reject(reason)
          }
        )
      })
    })
  }

  /**
   * myPromise对象的race()
   * 返回一个myPromise,结果由第一个完成的myPromise决定
   * 
   */
  myPromise.race = function (myPromises) {
    return new myPromise((resolve, reject) => {
      myPromises.forEach((p, index) => {
        myPromise.resolve(p).then(
          value => {
            // 第一个异步完成的且成功的直接返回成功的myPromise
            resolve(value)
          },
          reason => {
            // 第一个异步完成的且失败的直接返回失败的myPromise
            reject(reason)
          }
        )
      })
    })
  }

  // 向外暴露
  window.myPromise = myPromise
})(window)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值