理解Promise原理 手写Promise【实践】

注:
1.此文仅记录博主学习实践Promise技术之后的理解和总结,如有错误,敬请指正。
2.为突出promise核心思想,文章不涉及Promise细节和异常处理以及Promise的一些语法糖(如 Promise.all 、Promise.resolve 等等静态方法)。

一:实践收获

1.异步编程方案

  • 纯回调函数
  • 回调函数 + 监听机制 (回调函数改变状态并传递结果给一个容器,容器负责注册和实际调用回调行为)

2.Promise是什么

  • Promise通过回调函数 + 监听机制的方式来取代纯回调函数方式来实现异步编程
  • Promise是一个管理 异步逻辑结果的状态和数据 的容器对象

2.Promise优点

相比回调函数方式它有如下优点:

  • 可以解除异步逻辑及其回调行为的 耦合(目标维护一个观察者数组)
  • 多个有序的异步逻辑绑定 复用 一个异常回调方法(catch方法异常穿透)
  • Promise本身是一个异步操作结果状态和数据的容器,可以将异步逻辑的执行状态保留下来供后续使用。
  • 回调函数的执行是异步的(放入任务队列中),可以提升 性能
  • 可用 链式编码形式来表达多个有序的异步逻辑调用,可避免回调嵌套/地狱编码问题。(then方法构造并返回一个新的Promise,实现链式编程)。

3.Promise使用场景

  • 一个或多个有序异步逻辑时(使用async、await更佳)
  • 异步逻辑的结果状态和数据需要保存下来供后续逻辑使用时
  • 任何时候通过回调函数方式实现异步编程不够优雅时

4.最终得到的手写Promise精简版

function版
function Promise(excutor){
    
    

  // 实例属性
  this.status = Promise.PENDING
  this.data = null
  this.callbackArr = []
  const _this = this  

  // 实例方法
  function resolve(value) {
    
    
    _this.status = Promise.RESOLVED // 回调this指向window,_this通过作用域链访问外部this
    _this.data = value
    _this.callbackArr.forEach(item => {
    
    
      item.onResolved(this.data)
    })
  }
  // 失败回调
  function reject(reason) {
    
    
    _this.status = Promise.REJECTED
    _this.data = reason
    _this.callbackArr.forEach(item => {
    
    
      item.onRejected(this.data)
    });
  }
  excutor(resolve, reject)
}

// 静态属性
Promise.PENDING = 'pending'
Promise.RESOLVED = 'resolved'
Promise.REJECTED = 'rejected'

// 静态方法
Promise.prototype.then = function (onResolved, onRejected) {
    
    
  const _this = this
  // 回调函数是同步操作时涉及到两个Promise之间的关系(当前Promise A,返回的Promise B)
  // 回调函数是异步操作时涉及到三个Promise之间的关系(当前Promise A,返回的Promise B,回调函数返回的Promise C)
  // 关键认识:通知始终是在异步操作实际回调时发起的。
  return new Promise(function (resolve, reject) {
    
    
    let result = null
    switch (_this.status) {
    
    
      case Promise.PENDING:
        _this.callbackArr.push({
    
    
          onResolved:function() {
    
    
            result = onResolved(_this.data)// A通知C
            if(result instanceof Promise){
    
    
              // 异步
              result.then(resolve,reject)  // 等待C,C通知B(B的状态和结果都由C决定,B把改变自身通知方法resolve和reject交给C)
            }else{
    
    
              // 同步
              resolve(result)
            }
          }, 
          onRejected:function() {
    
    
            result = onRejected(_this.data)
            if(result instanceof Promise){
    
    
              result.then(resolve,reject)
            }else{
    
    
              onRejected(result)
            }
          }
        })
        break
      case Promise.RESOLVED:
        result = onResolved(_this.data)
        if(result instanceof Promise){
    
    
          result.then(resolve(result))
        }else{
    
    
          resolve(result)
        }
        break
      case Promise.REJECTED:
        result = onRejected(_this.data)
        if(result instanceof Promise){
    
    
          result.then(resolve(result))
        }else{
    
    
          resolve(result)
        }
        break
    }
  })
}
class版
(function(window){
    
    

  class Promise{
    
    

    // 抽取异步逻辑excutor
    constructor(excutor){
    
    
      this.state = Promise.PENDING // 监听的数据
      this.data = null  // 需通知数据
      this.observerArr = [] // 观察者数组
      excutor(this.resolve.bind(this), this.reject.bind(this))  // 因为resolve是被回调调用,这里强制绑定this,防止变化指向window
    }

    // 通知成功的方法
    resolve(value){
    
    
      this.state = Promise.RESOLVED //注意this指向
      this.data = value
      this.observerArr.forEach(item => {
    
    
        item.onResolved(this.data)
      })
    }

    // 通知失败的方法
    reject(reason){
    
    
      this.state = Promise.REJECTED
      this.data = reason
      this.observerArr.forEach(item => {
    
    
        item.onRejected(_this.data)
      });
    }

    // 添加观察者的方法
    then(onResolved,onRejected){
    
    
    const _this = this
    return new Promise(function (resolve, reject) {
    
    
      let result = null
      switch (_this.state) {
    
    
        case Promise.PENDING:
          _this.observerArr.push({
    
    
            onResolved:function() {
    
    
              result = onResolved(_this.data)
              if(result instanceof Promise){
    
    
                result.then(resolve,reject) // 通知授权,回调Promise的回调执行逻辑就是发起返回的Promise的通知
              }else{
    
    
                resolve(result)
              }
            }, 
            onRejected:function() {
    
    
              result = onRejected(_this.data)
              if(result instanceof Promise){
    
    
                result.then(resolve,reject) // 通知授权
              }else{
    
    
                reject(result)
              }
            }
          })
          break
        case Promise.RESOLVED:
          result = onResolved(_this.data)
          if(result instanceof Promise){
    
    
            result.then(resolve,reject) // 通知授权
          }else{
    
    
            resolve(result)
          }
          break
        case Promise.REJECTED:
          result = onRejected(_this.data)
              if(result instanceof Promise){
    
    
                result.then(resolve,reject) // 通知授权
              }else{
    
    
                reject(result)
              }
          break
      }
    })
    }
  }

  Promise.PENDING = 'pending'
  Promise.RESOLVED = 'pending'
  Promise.REJECTED = 'pending'

  window.Promise = Promise
})(window)

二:实现Promise:从0到1逐步实现需求

1.通过 回调函数 + 监听机制 机制实现异步编程

First:创建容器对象,在回调中接管异步操作结果的状态和数据

优点
  • 由于该容器对象的生命周期从异步操作定义时就创建,并且贯穿了该异步操作的定义、等待、结束,所以它可以在异步逻辑实际执行前 执行后都可以注册回调函数
  • 由于把回调函数交给了容器管理,所以通过监听机制实现可以解除异步逻辑及其回调行为的 耦合
定义(.js)
(function(window){
    
    
  function asyncFn(){
    
    
    const arm = new AsyncResultManager()
    setTimeout(
      function(){
    
    
        // 成功回调
        arm.status = AsyncResultManager.RESOLVED
        arm.data = 'success_data'
        // 失败回调
        // arm.status = AsyncResultManager.REJECTED
        // arm.data = 'error_reason'
        arm.resultHandler()
      }
    ,1000)
    return arm
  }
  function AsyncResultManager(){
    
    
    this.status = AsyncResultManager.PENDING
    this.data = null
  }
  AsyncResultManager.PENDING  = 'pending'
  AsyncResultManager.RESOLVED = 'resolved'
  AsyncResultManager.REJECTED = 'rejected'
  AsyncResultManager.prototype.resultHandler= function (){
    
    
    switch(this.status){
    
    
     case AsyncResultManager.RESOLVED:
        console.log(this.data)
        break
      case AsyncResultManager.REJECTED:
        console.log(this.data)
        break
    }
  }
  window.asyncFn = asyncFn
  window.AsyncResultManager = AsyncResultManager
})(window)
引用(.html)
 <script src='./MyPromise.js'></script>
  <script>
    const arm = asyncFn()// 成功回调,控制台输出success_data
    setTimeout(function(){
     
     
      // 被保存后的状态仍旧可以使用
      if(arm.status===AsyncResultManager.RESOLVED){
     
     
      console.log('success',arm.data) // 已就绪的成功状态,控制台输出success success_data
    }else if(arm.status===AsyncResultManager.REJECTED){
     
     
      console.log('error',arm.data)
    }
    },2000)
  </script>
输出

在这里插入图片描述

Second:封装成公用函数(暴露出且仅暴露出 调用者关注的异步操作及其成功、失败回调)

始终注意容器内回调函数的执行实际上都是由异步操作的回调中驱动的,所以需要把改变容器状态的行为控制权交还给异步操作(以参数的形式)。

第一步:抽取异步操作
  • 定义(.js)
(function(window){
    
    
  function asyncFnProxy(excutor){
    
    
    const arm = new AsyncResultManager()
    // 成功回调
    function success(){
    
    
      arm.status = AsyncResultManager.RESOLVED
      arm.data = 'success_data'
      arm.resultHandler()
    }
    // 失败回调
    function error(){
    
    
        arm.status = AsyncResultManager.REJECTED
        arm.data = 'error_reason'
        arm.resultHandler()
    }
    excutor(success,error)
    return arm
  }
  function AsyncResultManager(){
    
    
    this.status = AsyncResultManager.PENDING
    this.data = null
  }
  AsyncResultManager.PENDING  = 'pending'
  AsyncResultManager.RESOLVED = 'resolved'
  AsyncResultManager.REJECTED = 'rejected'
  AsyncResultManager.prototype.resultHandler= function (){
    
    
    switch(this.status){
    
    
      case AsyncResultManager.RESOLVED:
        console.log(this.data)
        break
      case AsyncResultManager.REJECTED:
        console.log(this.data)
        break
    }
  }
  // window.asyncFn = asyncFn
  window.asyncFnProxy = asyncFnProxy
  window.AsyncResultManager = AsyncResultManager
})(window)
  • 引用(.html)
  <script src='./lib/MyPromise.js'></script>
  <script>
    // const arm = asyncFn()
      const arm = asyncFnProxy(function(success,error){
     
     
      setTimeout(function(){
     
     
        console.log('async operation')
        const asyncResultData = 'success_data'
        success(asyncResultData)// 异步逻辑结果成功,执行成功回调
        // const asyncErrorReason = 'error_reason'
        // error(asyncErrorReason) // 异步逻辑结果失败,执行失败回调
      },100)
    })
   setTimeout(()=>{
     
     console.log('arm容器中异步操作结果的状态和数据更新之后');console.log(arm)},1000)
  </script>
  • 运行结果
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200810151622309.png
第二步:抽取回调函数
  • 定义(.js)
(function(window){
    
    
  function asyncFnProxy(excutor){
    
    
    const arm = new AsyncResultManager()
    // 成功回调
    function success(value){
    
    
      arm.status = AsyncResultManager.RESOLVED
      arm.data = value
      arm.resultHandler()
    }
    // 失败回调
    function error(reason){
    
    
        arm.status = AsyncResultManager.REJECTED
        arm.data = reason
        arm.resultHandler()
    }
    excutor(success,error)
    return arm
  }
  function AsyncResultManager(){
    
    
    this.status = AsyncResultManager.PENDING
    this.data = null
    this.callbackArr = []
  }
  AsyncResultManager.PENDING  = 'pending'
  AsyncResultManager.RESOLVED = 'resolved'
  AsyncResultManager.REJECTED = 'rejected'
  AsyncResultManager.prototype.addCallback = function (success,error){
    
    
    switch(this.status){
    
    
      case AsyncResultManager.PENDING:
        this.callbackArr.push({
    
    success,error})
        break
      case AsyncResultManager.RESOLVED:
        // 已成功,异步逻辑结束发送的一次性通知已经结束,若仍push至数组该回调将不会被执行
        success(this.data)
        break
      case AsyncResultManager.REJECTED:
        // 已失败,异步逻辑结束发送的一次性通知已经结束,若仍push至数组该回调将不会被执行
        error(this.data)
        break
    }
  }
  AsyncResultManager.prototype.resultHandler= function (){
    
    
    switch(this.status){
    
    
      case AsyncResultManager.RESOLVED:
        this.callbackArr.forEach(item => {
    
    
          item.success(this.data)
        });
        break
      case AsyncResultManager.REJECTED:
        this.callbackArr.forEach(item => {
    
    
          item.error(this.data)
        });
        break
    }
  }
  // window.asyncFn = asyncFn
  window.asyncFnProxy = asyncFnProxy
  window.AsyncResultManager = AsyncResultManager
})(window)
  • 使用(.html)
  <script src='./MyPromise.js'></script>
  <script>
    // const arm = asyncFn()
    const arm = asyncFnProxy(function(success,error){
    
    
      setTimeout(function(){
    
    
        console.log('async operation')
        // const asyncResultData = 'success_data'
        // success(asyncResultData)// 异步逻辑结果成功,执行成功回调
        const asyncErrorReason = 'error_reason'
        error(asyncErrorReason) // 异步逻辑结果失败,执行失败回调
      },100)
    })
    arm.addCallback(
      function(value){
    
    
        console.log('async success callback')
        console.log(value)
      },
      function(reason){
    
    
        console.log('async error callback')
        console.log(reason)
      }
    )
    setTimeout(()=>{
    
    console.log('arm容器中异步操作结果的状态和数据更新之后'); arm.addCallback(
      function(value){
    
    
        console.log('async success callback2')
        console.log(value)
      },
      function(reason){
    
    
        console.log('async error callback2')
        console.log(reason)
      }
    )},1000)

  </script>
  • 运行结果
    在这里插入图片描述

2.通过递归构造该容器实现链式调用

优点
  • 由于每次调用容器的添加回调方法时,也会创建一个容器对象来管理这个回调方法调用(下文实现仅支持同步调用,异步时可以再以与此异步操作同样的方式来进行)后的状态和结果,所以它可以实现以 同步编码形式来表达多个有序的异步 / 同步逻辑调用

支持同步链式调用

定义(.js)
(function (window) {
    
    
  function asyncFnProxy(excutor) {
    
    
    const arm = new AsyncResultManager()
    // 成功回调
    function success(value) {
    
    
      arm.status = AsyncResultManager.RESOLVED
      arm.data = value
      arm.resultHandler()
    }
    // 失败回调
    function error(reason) {
    
    
      arm.status = AsyncResultManager.REJECTED
      arm.data = reason
      arm.resultHandler()
    }
    excutor(success, error)
    return arm
  }
  function AsyncResultManager() {
    
    
    this.status = AsyncResultManager.PENDING
    this.data = null
    this.callbackArr = []
  }
  AsyncResultManager.PENDING = 'pending'
  AsyncResultManager.RESOLVED = 'resolved'
  AsyncResultManager.REJECTED = 'rejected'
  AsyncResultManager.prototype.addCallback = function (success, error) {
    
    
    const _this = this
    const arm2 = asyncFnProxy(function (resolve, reject) {
    
    
      // 1.添加回调监听 2.传递回调运行结果给下一个AsyncResultManager
      switch (_this.status) {
    
    
        case AsyncResultManager.PENDING:
          _this.callbackArr.push({
    
    
            success:function() {
    
    
              const value = success(_this.data)// 异步时,不能直接放回,会没有数据
              resolve(value)
            }, 
            error:function() {
    
    
              const reason = error(_this.data)
              reject(reason)
            }
          })
          break
        case AsyncResultManager.RESOLVED:
          const value = success(_this.data)
          resolve(value)
          break
        case AsyncResultManager.REJECTED:
          const reason = error(_this.data)
          reject(reason)
          break
      }
    })
    return arm2
  }
  AsyncResultManager.prototype.resultHandler = function () {
    
    
    switch (this.status) {
    
    
      case AsyncResultManager.RESOLVED:
        this.callbackArr.forEach(item => {
    
    
          item.success(this.data)
        });
        break
      case AsyncResultManager.REJECTED:
        this.callbackArr.forEach(item => {
    
    
          item.error(this.data)
        });
        break
    }
  }
  // window.asyncFn = asyncFn
  window.asyncFnProxy = asyncFnProxy
  window.AsyncResultManager = AsyncResultManager
})(window)
引用(.html)
 <script src='./lib/MyPromise.js'></script>
  <script>
    // const arm = asyncFn()
    const arm = asyncFnProxy(function(success,error){
     
     
      setTimeout(function(){
     
     
        console.log('async operation')
        const asyncResultData = 'success_data'
        success(asyncResultData)// 异步逻辑结果成功,执行成功回调
        // const asyncErrorReason = 'error_reason'
        // error(asyncErrorReason) // 异步逻辑结果失败,执行失败回调
      },1000)
    })
    const lastArm = arm.addCallback(
      function(value){
     
     
        console.log('running callback1')
        console.log(value)
        value = value + '_accessed1'
        return value
      },
      function(reason){
     
     
        console.log(reason)
        reason+='_access1'
        return reason
      }
    ).addCallback(
      function(value){
     
     
        console.log('running callback2')
        console.log(value)
        value = value + '_accessed2'
        return value
      },
      function(reason){
     
     
        console.log(reason)
        reason+='_accessed2'
        return reason
      }
    ).addCallback(
      function(value){
     
     
        console.log('running callback3')
        console.log(value)
        return value+'_accessed3'
      },
      function(reason){
     
     
        console.log(reason)
        return reason+'_accessed3'
      }
    )
    setTimeout(()=>{
     
     console.log('arm容器中异步操作结果的状态和数据更新之后'); lastArm.addCallback(
      function(value){
     
     
        console.log('running callback4')
        console.log(value)
      },
      function(reason){
     
     
        console.log(reason)
      }
    )},1000)

  </script>
运行结果

在这里插入图片描述

支持异步链式调用

定义(.js)
(function (window) {
    
    
  function asyncFnProxy(excutor) {
    
    
    const arm = new AsyncResultManager()
    // 成功回调
    function success(value) {
    
    
      arm.status = AsyncResultManager.RESOLVED
      arm.data = value
      arm.resultHandler()
    }
    // 失败回调
    function error(reason) {
    
    
      arm.status = AsyncResultManager.REJECTED
      arm.data = reason
      arm.resultHandler()
    }
    excutor(success, error)
    return arm
  }
  function AsyncResultManager() {
    
    
    this.status = AsyncResultManager.PENDING
    this.data = null
    this.callbackArr = []
  }
  AsyncResultManager.PENDING = 'pending'
  AsyncResultManager.RESOLVED = 'resolved'
  AsyncResultManager.REJECTED = 'rejected'
  AsyncResultManager.prototype.addCallback = function (success, error) {
    
    
    const _this = this
    const arm2 = asyncFnProxy(function (resolve, reject) {
    
    
      let result = null
      // 1.添加回调监听 2.传递回调运行结果给下一个AsyncResultManager 3.回调为异步操作时,把返回的AsyncResultManager的通知授权给回调的AsyncResultManager
      switch (_this.status) {
    
    
        case AsyncResultManager.PENDING:
          _this.callbackArr.push({
    
    
            success:function() {
    
    
              result  = success(_this.data)
              if(result instanceof AsyncResultManager){
    
    
                result.addCallback(resolve,reject)
              }else{
    
    
                resolve(result)
              }
            }, 
            error:function() {
    
    
              result  = error(_this.data)
              if(result instanceof AsyncResultManager){
    
    
                result.addCallback(resolve,reject)
              }else{
    
    
                reject(result)
              }
            }
          })
          break
        case AsyncResultManager.RESOLVED:
          result  = success(_this.data)
          if(result instanceof AsyncResultManager){
    
    
            result.addCallback(resolve,reject)
          }else{
    
    
            resolve(result)
          }
          break
        case AsyncResultManager.REJECTED:
          result  = error(_this.data)
          if(result instanceof AsyncResultManager){
    
    
            result.addCallback(resolve,reject)
          }else{
    
    
            reject(result)
          }
          break
      }
    })
    return arm2
  }
  AsyncResultManager.prototype.resultHandler = function () {
    
    
    switch (this.status) {
    
    
      case AsyncResultManager.RESOLVED:
        this.callbackArr.forEach(item => {
    
    
          item.success(this.data)
        });
        break
      case AsyncResultManager.REJECTED:
        this.callbackArr.forEach(item => {
    
    
          item.error(this.data)
        });
        break
    }
  }
  // window.asyncFn = asyncFn
  window.asyncFnProxy = asyncFnProxy
  window.AsyncResultManager = AsyncResultManager
})(window)
引用(.html)
  <script src='./check.js'></script>
  <script>
   const arm = asyncFnProxy(function(success,error){
     
     
      setTimeout(function(){
     
     
        console.log('async operation')
        const asyncResultData = 'success_data'
        success(asyncResultData)// 异步逻辑结果成功,执行成功回调
        // const asyncErrorReason = 'error_reason'
        // error(asyncErrorReason) // 异步逻辑结果失败,执行失败回调
      },1000)
    })
    const lastArm = arm.addCallback(
      function(value){
     
     
        console.log('running callback1')
        console.log(value)
        value = value + '_accessed1'
        return value
      },
      function(reason){
     
     
        console.log(reason)
        reason+='_access1'
        return reason
      }
    ).addCallback(
      function(value){
     
     
        console.log('running callback2')
        console.log(value)
        value = value + '_accessed2'
        return asyncFnProxy(function(success,error){
     
     
      setTimeout(function(){
     
     
        console.log('async operation')
        value = value + '_async'
        success(value)// 异步逻辑结果成功,执行成功回调
      },1000)
    })
      },
      function(reason){
     
     
        console.log(reason)
        reason+='_accessed2'
        return reason
      }
    ).addCallback(
      function(value){
     
     
        console.log('running callback3')
        console.log(value)
        return value+'_accessed3'
      },
      function(reason){
     
     
        console.log(reason)
        return reason+'_accessed3'
      }
    )
    setTimeout(()=>{
     
     console.log('arm容器中异步操作结果的状态和数据更新之后'); lastArm.addCallback(
      function(value){
     
     
        console.log('running callback4')
        console.log(value)
      },
      function(reason){
     
     
        console.log(reason)
      }
    )},1000)

  </script>
运行结果

在这里插入图片描述

3.调整代码,使其更贴近真实的Promise设计

定义(.js)
function Promise(excutor){
    
    

  // 实例属性
  this.status = Promise.PENDING
  this.data = null
  this.callbackArr = []
  const _this = this  

  // 实例方法
  function resolve(value) {
    
    
    _this.status = Promise.RESOLVED // 回调this指向window,_this通过作用域链访问外部this
    _this.data = value
    _this.callbackArr.forEach(item => {
    
    
      item.onResolved(this.data)
    })
  }
  // 失败回调
  function reject(reason) {
    
    
    _this.status = Promise.REJECTED
    _this.data = reason
    _this.callbackArr.forEach(item => {
    
    
      item.onRejected(this.data)
    });
  }
  excutor(resolve, reject)
}

// 静态属性
Promise.PENDING = 'pending'
Promise.RESOLVED = 'resolved'
Promise.REJECTED = 'rejected'

// 静态方法
Promise.prototype.then = function (onResolved, onRejected) {
    
    
  const _this = this
  // 回调函数是同步操作时涉及到两个Promise之间的关系(当前Promise A,返回的Promise B)
  // 回调函数是异步操作时涉及到三个Promise之间的关系(当前Promise A,返回的Promise B,回调函数返回的Promise C)
  // 关键认识:通知始终是在异步操作实际回调时发起的。
  return new Promise(function (resolve, reject) {
    
    
    let result = null
    switch (_this.status) {
    
    
      case Promise.PENDING:
        _this.callbackArr.push({
    
    
          onResolved:function() {
    
    
            result = onResolved(_this.data)// A通知C
            if(result instanceof Promise){
    
    
              // 异步
              result.then(resolve,reject)  // 等待C,C通知B(B的状态和结果都由C决定,B把改变自身通知方法resolve和reject交给C)
            }else{
    
    
              // 同步
              resolve(result)
            }
          }, 
          onRejected:function() {
    
    
            result = onRejected(_this.data)
            if(result instanceof Promise){
    
    
              result.then(resolve,reject)
            }else{
    
    
              onRejected(result)
            }
          }
        })
        break
      case Promise.RESOLVED:
        result = onResolved(_this.data)
        if(result instanceof Promise){
    
    
          result.then(resolve(result))
        }else{
    
    
          resolve(result)
        }
        break
      case Promise.REJECTED:
        result = onRejected(_this.data)
        if(result instanceof Promise){
    
    
          result.then(resolve(result))
        }else{
    
    
          resolve(result)
        }
        break
    }
  })
}
引用(.html)
<script src='./check.js'></script>
  <script>
    const promise = new Promise(function (resolve, reject) {
     
     
      setTimeout(function () {
     
     
        console.log('async operation')
        const asyncResultData = 'success_data'
        resolve(asyncResultData)// 异步逻辑结果成功,执行成功回调
        // const asyncErrorReason = 'error_reason'
        // error(asyncErrorReason) // 异步逻辑结果失败,执行失败回调
      }, 1000)
    })
    const lastPromise = promise.then(
      function (value) {
     
     
        console.log('promise1 callback')
        console.log(value)
        value = value + '_accessed1'
        return value
      },
      function (reason) {
     
     
        console.log(reason)
        reason += '_access1'
        return reason
      }
    ).then(
      function (value) {
     
     
        console.log('promise2 callback')
        console.log(value)
        value = value + '_accessed2'
        return new Promise(function (resolve, reject) {
     
     
          setTimeout(function () {
     
     
            console.log('async operation')
            value+='_async'
            resolve(value)// 异步逻辑结果成功,执行成功回调
          }, 1000)
        })
      },
      function (reason) {
     
     
        console.log(reason)
        reason += '_accessed2'
        return reason
      }
    ).then(
      function (value) {
     
     
        console.log('promise3 callback')
        console.log(value)
        return value + '_accessed3'
      },
      function (reason) {
     
     
        console.log(reason)
        return reason + '_accessed3'
      }
    )
    setTimeout(() => {
     
     
      lastPromise.then(
        function (value) {
     
     
          console.log('promise4 callback')
          console.log(value)
        },
        function (reason) {
     
     
          console.log(reason)
        }
      )
    }, 1000)

  </script>
运行结果

在这里插入图片描述

三:实现Promise:观察者设计模式一步到位

使用观察者设计模式来实现监听机制。

1.实现前思考

  • 目标是什么?观察者是什么?目标与观察者之间的关系是怎样,数据结构如何设计?
  • 目标与观察者之间的关系如何建立?何时建立?
  • 目标如何通知观察者触发对应行为?何时通知?

2.实现分析:目标对象

目标属性
  • 监听的数据:异步逻辑操作结束后的结果状态
  • 需通知数据:异步逻辑操作结束后的结果数据 value / reason
  • 观察者数组:回调对象(成功回调、失败回调)
目标行为
  • 通知:成功通知 resolve、失败通知 reject
  • 添加观察者:添加回调对象 then、catch
业务构造
  • 参数:异步逻辑函数excutor(因为excutor与subject是一对一的关系,且excutor是用户使用Promise真正的关注点之一,故为了更好地封装和调用,将其作为subject的构造参数)
  • 行为:构造对象、授权通知行为(真正驱动通知【即调用resolve和reject方法】是在excutor真正的回调方法中,如setTimeOut( fn,delay))中的fn。

3.实现分析:观察者对象

属性
行为
  • 通知时被调用方法:success 成功回调、error失败回调
业务构造
  • 参数:成功回调、错误回调(为了更好的封装,抽取异步操作的回调方法。因为调用者使用Promise真正关注的只有异步操作和回调行为二者,其它的都应该对调用者屏蔽)。
  • 行为:构造对象

4.具体实现

1.定义(.js)
(function(window){
    
    

  class Subject{
    
    

    // 封装异步逻辑、抽取异步逻辑、授权异步逻辑(将目标的通知方法授权给回调逻辑)
    constructor(excutor){
    
    
      this.state = Subject.PENDING // 监听的数据
      this.data = null  // 需通知数据
      this.observerArr = [] // 观察者数组
      excutor(this.resolve.bind(this), this.reject.bind(this))  // 因为resolve是被回调调用,这里强制绑定this,防止变化指向window
    }

    // 通知成功的方法
    resolve(value){
    
    
      this.state = Subject.RESOLVED //注意this指向
      this.data = value
      this.observerArr.forEach(item => {
    
    
        item.onResolved(this.data)
      })
    }

    // 通知失败的方法
    reject(reason){
    
    
      this.state = Subject.REJECTED
      this.data = reason
      this.observerArr.forEach(item => {
    
    
        item.onRejected(_this.data)
      });
    }

    // 添加观察者的方法
    then(observer){
    
    
    const _this = this
    return new Subject(function (resolve, reject) {
    
    
      let result = null
      switch (_this.state) {
    
    
        case Subject.PENDING:
          _this.observerArr.push({
    
    
            onResolved:function() {
    
    
              result = observer.onResolved(_this.data)
              if(result instanceof Subject){
    
    
                result.then(new Observer(resolve,reject))// 通知授权
              }
              else{
    
    
                resolve(result)
              }
            }, 
            onRejected:function() {
    
    
              result = observer.onRejected(_this.data)
              if(result instanceof Subject){
    
    
                result.then(new Observer(resolve,reject))// 通知授权
              }
              else{
    
    
                reject(result)
              }
            }
          })
          break
        case Subject.RESOLVED:
          result = observer.onResolved(_this.data)
          if(result instanceof Subject){
    
    
            result.then(new Observer(resolve,reject))// 通知授权
          }
          else{
    
    
            resolve(result)
          }
          break
        case Subject.REJECTED:
          result = observer.onRejected(_this.data)
          if(result instanceof Subject){
    
    
            result.then(new Observer(resolve,reject))// 通知授权
          }
          else{
    
    
            reject(result)
          }
          break
      }
    })
    }
  }

  Subject.PENDING = 'pending'
  Subject.RESOLVED = 'pending'
  Subject.REJECTED = 'pending'


  class Observer{
    
    
    // 抽取回调函数
    constructor(onResolved,onRejected){
    
    
      this.onResolved = onResolved
      this.onRejected = onRejected
    }
    // onResolved(){} // 被抽取到构造函数由用户定制了
    // onRejected(){} // 被抽取到构造函数由用户定制了
  }

  window.Subject = Subject
  window.Observer = Observer
})(window)
引用(.html)
<script src='./check.js'></script>
  <script>
    const subject = new Subject(function(resolve,reject){
     
     
      setTimeout(function(){
     
     
        console.log('async operation')
        const asyncResultData = 'success_data'
        resolve(asyncResultData)// 异步逻辑结果成功,执行成功回调
      },1000)
    })
    const lastSubject = subject.then(new Observer(
      function(value){
     
     
        console.log('subject1 callback')
        console.log(value)
        value = value + '_accessed1'
        return value
      },
      function(reason){
     
     
        console.log(reason)
        reason+='_access1'
        return reason
      }
    )
    
    ).then(
      new Observer(function(value){
     
     
        console.log('subject2 callback')
        console.log(value)
        value = value + '_accessed2'
        return new Subject(function(resolve,reject){
     
     
      setTimeout(function(){
     
     
        console.log('async operation')
        value = value + '_async'
        resolve(value)// 异步逻辑结果成功,执行成功回调
      },1000)
    })
      },
      function(reason){
     
     
        console.log(reason)
        reason+='_accessed2'
        return reason
      })
    ).then(
      new Observer(
        function(value){
     
     
        console.log('subject3 callback')
        console.log(value)
        return value+'_accessed3'
      },
      function(reason){
     
     
        console.log(reason)
        return reason+'_accessed3'
      }
      )
    )
    setTimeout(()=>{
     
     lastSubject.then(
      new Observer(  function(value){
     
     
        console.log('subject4 callback')
        console.log(value)
      },
      function(reason){
     
     
        console.log(reason)
      })
    )},1000)

  </script>
运行结果

在这里插入图片描述

5.调整代码,使其更贴近真实的Promise设计

(function(window){
    
    

  class Promise{
    
    

    // 抽取异步逻辑excutor
    constructor(excutor){
    
    
      this.state = Promise.PENDING // 监听的数据
      this.data = null  // 需通知数据
      this.observerArr = [] // 观察者数组
      excutor(this.resolve.bind(this), this.reject.bind(this))  // 因为resolve是被回调调用,这里强制绑定this,防止变化指向window
    }

    // 通知成功的方法
    resolve(value){
    
    
      this.state = Promise.RESOLVED //注意this指向
      this.data = value
      this.observerArr.forEach(item => {
    
    
        item.onResolved(this.data)
      })
    }

    // 通知失败的方法
    reject(reason){
    
    
      this.state = Promise.REJECTED
      this.data = reason
      this.observerArr.forEach(item => {
    
    
        item.onRejected(_this.data)
      });
    }

    // 添加观察者的方法
    then(onResolved,onRejected){
    
    
    const _this = this
    return new Promise(function (resolve, reject) {
    
    
      let result = null
      switch (_this.state) {
    
    
        case Promise.PENDING:
          _this.observerArr.push({
    
    
            onResolved:function() {
    
    
              result = onResolved(_this.data)
              if(result instanceof Promise){
    
    
                result.then(resolve,reject) // 通知授权,回调Promise的回调执行逻辑就是发起返回的Promise的通知
              }else{
    
    
                resolve(result)
              }
            }, 
            onRejected:function() {
    
    
              result = onRejected(_this.data)
              if(result instanceof Promise){
    
    
                result.then(resolve,reject) // 通知授权
              }else{
    
    
                reject(result)
              }
            }
          })
          break
        case Promise.RESOLVED:
          result = onResolved(_this.data)
          if(result instanceof Promise){
    
    
            result.then(resolve,reject) // 通知授权
          }else{
    
    
            resolve(result)
          }
          break
        case Promise.REJECTED:
          result = onRejected(_this.data)
              if(result instanceof Promise){
    
    
                result.then(resolve,reject) // 通知授权
              }else{
    
    
                reject(result)
              }
          break
      }
    })
    }
  }

  Promise.PENDING = 'pending'
  Promise.RESOLVED = 'pending'
  Promise.REJECTED = 'pending'

  window.Promise = Promise
})(window)

猜你喜欢

转载自blog.csdn.net/jw2268136570/article/details/107905569