axios拦截器、中间件和发布订阅模式杂谈

Axios拦截器的关键实现。

  1. 首先看Axios源码lib/core/Axios.js文件,这里是Axios方法的源码。非常简洁。用defaults保存用户创建axios对象时传入的自定义配置。还有一个interceptors对象,英文翻译过来就是拦截器,那么我们就可以知道这个对象用来保存axios的拦截器。Axios拦截器有请求拦截器和响应拦截器,所以它用request和response两个变量去保存各自的拦截器。
    Axios类
  2. 所以我们接下来要看InterceptorManager这个方法的源码,它在lib/core/interceptorManager.js文件中。interceptorManager里面只有一个handles数组。暂时还不知道这个数组的作用是什么。我们平时使用拦截器是通过调用拦截器对象的use()方法传入我们的回调函数。对请求真正发出去之前,先调用我们的回调函数处理配置对象。所以要知道handles数组有什么用,我们还需要查看拦截器的use()原型方法对我们传入的回调做了什么处理。这里我们看到了handles数组的身影,use方法把我们传入的回调放在一个对象里面推进了handles数组里面。我们可以把这一步称为任务注册。将拦截处理的回调方法保存到handlers数组里面。
    在这里插入图片描述
  3. use方法还返回了当前注册任务handlers数组的下标,这里是提供一个id用于清除拦截器,类似setTimeout的返回值用于清除改定时器。该下表可以传给拦截器eject原型方法去清除该拦截器,源码如下。在这里插入图片描述
  4. 了解了拦截器如果进行任务注册后,我们还需要Axios如果对这些任务进行编排才能达到在请求发送前拦截处理、发送请求、响应后拦截处理这种效果。我们需要查看Axios的request原型方法,Axios的所有请求发送都会调用这个方法,去完成请求发送前处理,发送请求,响应返回后处理。包括axios的get、post这些别名方法最终都会调用request方法去真正发送请求。
    在这里插入图片描述
  5. Axios的request方法先将请求拦截处理回调从头部添加进chain调用链数组,将响应拦截处理回调从尾部添加进调用链,中间就是dispatchRequest函数用于真正发送请求,这样就完成了任务编排。最后将拦截处理回调从调用链里的头部依次弹出传入promise里执行就完成了任务调用。这样就实现了配置发送请求前处理、发送请求、响应返回后处理这一个完整的过程的处理接口给开发人员去控制。有些人可能会好奇为什么最开始的调用链第二个元素是一个undefined,因为每次要从调用链里弹出两个元素传给promise的成功回调和失败回调。这个undefined是用来占位的。

    因为可以注册多个请求拦截和多个响应拦截,这样先注册的请求拦截因为从头部添加进调用链,所以在所有请求拦截里面是后面才得到执行的,而响应拦截就是按照你所写的顺序去调用处理的。

  6. 这就是Axios拦截器关键实现的所有啦。。。大家觉得写的还可以,可以给我点个赞呀。

数组和回调函数的组合碰撞

  1. 从上面我们看到Axios通过将拦截处理回调方法放进一个数组,然后在合适的时机遍历这个数组,取出里面的方法依次执行完成请求和响应拦截处理的功能。
  2. 其实有很多框架或者设计思想都会使用这种数组和函数结合的方式去搭建自己框架的一些底层应用。
  3. 使用到这种方式的有发布订阅模式Axios的拦截器koa和egg框架的中间件BetterScroll2.0的插件化架构设计。我们来看看他们的数组和回调函数组合能碰撞出怎样的火花。
一、发布订阅模式
  1. 发布订阅模式还有一个兄弟就是观察者模式,简单说一下他们的区别。首先他们都是为了实现消息分发这个功能。但是发布订阅就好像你刚下载了一个软件第一次打开,他会让你选择感兴趣的标签,以后会推送这些内容给你。发布订阅就是你不想收到所有消息,你只希望收到你感兴趣的消息。而观察者模式就没有区分,观察者发布的所有消息,被观察者都会收到。
    在这里插入图片描述
  2. 发布订阅模式是许多前端库的基础工具类,其作用不言而喻。发布订阅模式的简单实现如下。我们可以看到发布订阅通过on方法先判断handlers对象里是否存在传入的eventName的数组,如果没有就创建一个空数组,有就直接将回调添加到该数组的尾部,通过emit方法遍历handles对象的eventName数组拿出所有订阅者传入的回调执行实现消息分发。
    在这里插入图片描述
  3. 观察者模式的简单实现:代码中的区别就是handles的区别,发布订阅模式handles是一个对象,而观察者模式handles是一个数组。
    在这里插入图片描述
二、Axios的拦截器
  1. 这里前文讲过了,就不细说了,以下是Axios拦截器的关键实现部分,同样也是使用了将回调保存到数组里面遍历数组执行完成拦截器功能。
    在这里插入图片描述
三、koa和egg框架的中间件、洋葱模型
  1. 如果用nodeJs写过一些后端的话应该知道,后端会经常使用各种各样的中间件的完成功能开发。刚开始用中间件的时候就有一点奇怪,为什么总会有一个next参数,并且要在方法体里面通过执行next()才会继续执行下一个中间件。实现中间件后以下代码会依次打印出1,2,3,4,5,6有点类似“递归”。
    图4
  2. 我们先看koa的use原型方法,它将中间件的回调推进了存放中间件的数组,return this是为了支持链式调用添加中间件。koa实例通过调用listen方法启动服务器,在里面传入了callback方法,在callback方法里面终于看到了middleware中间数组。compose函数就是中间件实现的核心,他接受一个中间件数组参数。
    在这里插入图片描述
  3. compose方法使用i作为当前调用中间件在middleware的下标,通过middleware[i]取出中间件,然后再Promise.resolve里面调用,注意第二个参数dispatch.bind(null, i + 1)就是中间件的第二个参数next,通过在中间件方法体内执行next()调用执行dispatch.bind(null, i + 1)方法,而i+1是下一个中间件的下标,所以在中间件方法体里面执行next()就是为了调用下一个中间件。通过此种方法实现了上面代码顺序打印出1、2、3、4、5、6,实现了koa的中间件。
    在这里插入图片描述
四、BetterScroll2.0的插件化架构设计
  1. 详情查看BetterScroll 2.0 发布:精益求精,与你同行
  2. BetterScroll2.0版本的初衷来源于社区的一个需求,能不能支持按需加载。
  3. 这里BetterScroll2.0的插件化也是大概通过use方法,将插件构造器方法放进一个数组,然后循环这个数组判断当前元素是否是一个方法,如果是一个方法就创建这个插件实例实现插件化。
感想
  1. 看到use就要想到这极大可能是一个任务注册,把你传入的回调放进了一个数组里保存起来。
  2. 这种把回调放进一个数组,在合适的时机取出来调用的方式真的可以写出很漂亮的代码,实现很强大的功能。以上四个例子共通地方是都有任务注册,即把回调保存到数组里。区别在于在什么时候,以什么方式把回调取出来去执行,如果你也想到一种跟以上不同的方式去取里面的回调执行那可能也是一种新的强大的功能。

总结

  1. JavaScript有两个很重要的性质
    1. 在JavaScript中,函数是一等公民。
      1. 什么是一等公民?变量就是一等公民
      2. 变量可以赋值给其他变量
      3. 变量可以作为函数参数
      4. 变量可以作为函数返回值
      5. 变量可以做的,JavaScript中的函数同样可以,这就是一等公民。
      6. 也因为如此,所以才有了上述这些强大功能的实现。
    2. 在JavaScript里,一切都是对象。
      1. 这句话的意思不是说JavaScript的函数、数组等本质上都是对象,有一些浅显。而是应该理解为要把复杂的问题抽象成一个对象,然后去解决这个复杂问题。
      2. 第一次有这种感受是阅读babel编译原理的时候,babel编译原理将ES6转换成ES5大概是通过词法分析将字符串形式的代码转换成一个一个token,然后通过语法分析将这些token转换成AST,这个AST就是一个对象,这个对象包含了ES6代码的关键信息,这样要转换成ES5代码,我们只需要将AST的代码关键信息拿出来放进ES5语法里就完成了转换。实际过程极为复杂。
      3. 第二次有这种感受是前端框架的VDOM。同样也是通过将DOM的节点信息保存到对象里去高效渲染DOM节点。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Vgbire

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值