zoukankan      html  css  js  c++  java
  • 前端通信:ajax设计方案(十)--- 完善Promise A+规范,增加mock数据功能

    半年不迭代,迭代搞半年,说的就是我,这里有点尴尬了,直接进入主题吧

    我记得在这篇博客的时候集成了Promise的,不过那个时候就简简单单的写了一点最基础,在一些特殊的case上,还是有点问题的,所以才有了这个博客。在拜读了w3c和PromiseA+规范之后,从头到尾详细的了解了Promise这个东西,然后自己亲手写了一个和es6文档拥有相同功能的库。

    什么是promise?

    promise是一个对象,表示单个异步操作的最终结果。

    什么时候使用?

    任何一门技术都不是一个“万金油”,只有在它最合适的场地出现,才是实现它最大价值的地方,so,Promise一样逃不过这个“真香”定律。

    1. one-and-done操作模型

      • 异步I / O操作:从存储API读取或写入的方法可以返回承诺。
      • 异步网络操作:通过网络发送或接收数据的方法可以返回承诺。
      • 长时间运行的计算:需要一段时间来计算某些东西的方法可以在另一个线程上完成工作,返回结果的承诺。
      • 用户界面提示:要求用户回答的方法可以返回承诺。

    2. One-Time "Events”模型

      即使在已经履行或被拒绝之后也可以订阅,当某些事情只发生一次,并且作者经常想要在它已经发生之后观察它的状态

    3.更多状态的变化

      图像,字体等资源的加载loaded属性,这个属性仅在资源完全加载是才会实现,否则拒绝

     

    不建议使用promise的场景

    1. 任何一个可能不止一次发生的事件,都不是one-and-done模型的

    2. 大的流数据,分步处理流数据,而无需将流的全部内容缓冲到内存中。

     

    这里有个w3c组织搞出来的一个指南--Writing Promise-Using Specifications,建议大家拜读一下,虽然没有详细讲解规范,但是对于Promise使用场景和特性做了一次详细的介绍,包括我上面说的使用场景等等。

     

    以上讲的更多偏向应用层的知识点,下面就让我们深入它的根本去了解Promise是如何实现的。

    Promise本身是一种社区规范--Promises/A+,由Promise A+组织进行制定,它们提供了一个大纲和指导性的方案,只要能实现其所列规范,都可以视作实现了Promise A+,so,后面的各种变种啊,什么样的功能,都可以根据自己所需去设计,但是基础的方案按照A+ 组织规范实现就可以。

    这个大纲比较啰嗦、枯燥、无味,so,我们靠3张我画的图去理解一下Promise

     

    第一张:promise整体流程图

    1.  实例化Promise的时候(定义内部状态的初始值等等),在同步状态下,首先会执行初始化代码,比如:new Promise((res,rej)=>{ console.log('这里就是初始化代码') }),然后再执行then方法。这个执行顺序在promise下是错误的,因为在实例代码中会首先改变Promise状态,但是前置的callback还没有在then方法中注入,所以要做推迟实例代码(setTimeout,可以将任务推到执行周期之后,宏任务),让then先跑起来,注入状态变更需要的前置依赖。

    2.  在Promise规范中定义了,then方法,必须返回一个Promise,so,Promise2就是then的返回值。然后then的动作就是将所有需要前置依赖的回调函数,Promise状态,状态变化的value全都存储起来。

    3.  等待推迟的实例代码(官方叫:异步)执行之后,触发了Promise状态的变化这个动作,然后去改变内部定义的状态,以及状态变化所要执行的操作。

    4.  内部状态已经变化完成,但是return的Promise2状态还是pending,所以我们需要将自身的Promise和Promise2的状态进行同步以及是否可then的持续操作。

     

    以上为Promise的整体流程思路,它就是这样跑起来的。不过知道这个流程以后,还是一知半解的,下面我们就对核心方法then进行详细剖析。

     

    第二张:then方法核心解析

    then方法需要分3个状态去解析

    1. pending 状态

      a. 首先实例化执行then方法,这个时候初始化的内部状态都是pending,这个时候,我们要做一个订阅和发布的设计,将then传入的resolve和reject的回调进行包装和存储,并订阅触发动作。(这边的包装是因为订阅的时候,不仅仅只是执行回调函数,还需要处理promise2的状态同步问题)

      b. 在等待出发的状态的时候,这个时候状态没有变更,所以还是keep pending状态,而promise2也是pending;当promise触发了resolve,这个时候就需要处理之前订阅的回调了,先改变Promise自身的状态,然后调用callback,将callback的值传入解析函数,同步改变Promise2的状态;触发reject动作和resolve一样

      c. 这样,在整个pending链路上,自身状态和promise2状态全都同步改变完成

    2. resolve 状态

      a. Promise内部状态以及变更完毕,内部会存储PromiseValue的值,直接获取PromiseValue的值作为参数,调起then方法传进来的resolveCallback的函数。

      b. 使用同步解析函数,去同步改变Promise2的状态,以及后续可then的操作

    3. reject 状态 

      该状态操作,同resolve操作,只是变更状态不一样

     

    以上为then方法的所有操作流程,pending的时候最特殊,有个订阅发布设计来改变自身状态,然后同步改变Promise2的状态。其他resolve和reject,都是状态已经变更完毕,直接取状态变更的值,处理回调,然后同步改变Promise2的状态值。这边同步变更Promise2的规则,在A+的规范里是有定义的。

     

    第三张:同步改变Promise2状态以及是否可继续then的操作

    状态同步改变和是否可持续then的操作解析流程,都按照A+规范去判断

    1. x代表callback的返回值,首先判断x和Promise2是否相等,相等抛出TypeError的错误(毕竟如果返回值x和Promise2是一个对象的话,那操作就没啥意义了)

    2. 判断x是否是Promise对象,如果是的话,说明x是可支持then的,然后根据x的状态进行操作和同步改变Promise2的值,pending就等待执行结束,resolve和reject就分别改变Promise2的状态

    3. 如果x不是Promise对象,判断x是否是对象或者function,否的话直接resolve Promise2状态。如果是的话,try-catch捕获,定义then = x.then是否报错,如果报错则reject掉Promise2状态。

    4. 判断then是否是function,如果是则执行then操作,如果then方法执行了reject,则reject掉Promise2。

    5. 如果then执行resolve,则将y替换掉x,重新和Promise2进行状态的同步改变。

     

    PS:这里的x.then就是下面的这种状况,A+规范定义这样的返回值代表还是可then的,需要处理

      temp.then(function (x) {
        return {
          then: function(resolve, reject) {
            resolve(42);
          }
        }
      })

     

    至此整个Promise就结束了,从Promise怎么去运行,到核心代码then的处理,以及Promise2的同步改变,这就是所谓的Promise。回过头来发现,最值得佩服的是这种规范的设计思维,通过一种设计思维,将简单的技术化腐朽为神奇。所以,个人意见,程序员的进阶,最重要的不是代码的熟练度,而是思维的进阶。熟练度这个是每个人都可以靠时间堆积出来的,但是更高级的工程师,应该能从整体的视角去了解,然后规划和设计,将简单的技术化神奇,将复杂的问题化简单。

    整个代码我就不贴出来了,太长了,可以到 github 上查看,功能完善了,支持all、race、resolve、reject方法

     

    在ajax-js的库的变动,如下:

    1. 替换之前有问题的createPromise的代码

    2. 将get、post、postForm,obtainBlob,upload进行改造,改方法返回都是Promise(考虑这些都是one-and-done模型,而轮询和大文件切割上传2个方法是持续性操作,所以不做改变)

    3. 删除postJSON、promiseAjax方法

     

    ajax-js库增加新功能:mock功能

    全局配置参数:

        // mock功能
        mock: {
          isOpen: true,
          mockData: {}
        },

     

    流程如下:

     

    demo:

    // 全局配置
    ajax.config({
      baseURL:'http://localhost:3000/',
      mock: {
        isOpen:true,
        mockData: {
          'post':'我是mock数据'
        }
      }
    })
    
    // 测试代码
    function request_post() {
      ajax.post('post',{data:'ajaxPost'})
        .then(x=>{
          console.warn(x)
        })
    }

     

    测试结果:

     

    注意:mockData的key是url的值,不是baseUrl+url的值

     

     结束语:

    ajax-js.1.9.2完成了,一直在思考还有什么需要改进的东西,之后的迭代需要走的方向

    1. 完成http其他协议,put、delete等等

    2. npm的包面向现代化,去除各种polyfill和一些兼容代码

    3. 配置webpack自动打包压缩

    4. 探索通信和其他技术的结合玩法

    5. 等等...

     

    github地址:https://github.com/GerryIsWarrior/ajax   对你有帮助或启发,点个小星星,支持继续研究下去

  • 相关阅读:
    2. jvm-sandbox之结构和状态
    1. jvm-sandbox之小试牛刀
    redux中间件来执行异步操作
    redux
    vue简单插件
    VUE搭建
    用element-ui进行文件的上传
    完整的node脚手架搭建服务
    使用node来搭建简单的后台业务
    解决vuex数据页面刷新后初始化问题
  • 原文地址:https://www.cnblogs.com/GerryOfZhong/p/10726306.html
Copyright © 2011-2022 走看看