axios
axios 是目前前端常用的 HTTP 请求框架,地位几乎等同于几年前的 jQuery 的 ajax。为什么 axios 现在这么多人使用,笔者看来大概是因为一下几个方面
- 前端模块化的大势所趋
- axios 很多强大的功能特性
- Promise 的普及
个人认为以上三点是最主要的原因,下面切入正题,本文将对笔者在实际开发中关于 axios 的 Interceptors 和 CancelToken 做一个简单的阐述。
Interceptors 拦截器
axios 的 Interceptors(拦截器,以下统称拦截器),应该说是 axios 最为强大的功能之一,尽管 jQuery 的 ajax 也可以使用拦截器(jQuery 中 ajax 的 beforeSend 方法),但是它只能对单个请求进行拦截,无法做到统一配置。
前端开发是本着代码简短强悍(lazy)为目标的,因此能够统一配置拦截器的 axios 自然受到了开发者的追捧。
拦截器分为两种,分别是 request 拦截器和 response 拦截器,顾名思义,分别作用于一个 http 请求的 request 阶段(之前)和 response 阶段(拿回响应进行回调之前)。
大致用法如下
request 拦截器
// http request 拦截器 |
response 拦截器
// http response 拦截器 |
以上大概很多开发者都会使用,下面我们着重说一下 axios 的 CancelToken
CancelToken
CancelToken,字面意思的取消一个 Token 令牌。它的作用和 jQuery 中 ajax 的 abort 效果是一样的,就是掐掉这个请求。
可能会有笔者会问,axios 是基于 Promise 实现的,Promise 状态一但确立,不是不能改变吗(就是说不能取消一个进行中的 Promise,让它既不能 resolve,也不能 reject)?
这个问题,得回到 Promise 的 T39 对于 Promise/A+的提案上去(关于 Promise/A+)
因为 T39 协会想的是 Promise 既然是一个状态机,那么必然应有且只有 2 中状态,Yes or No,对应 resolve 和 reject(注意这里说的是状态,不是方法)
其实社区对于 Promise 的 cancel 是有一个提案的(已经被撤回),具体参考proposal-cancelable-promises
尽管该提案已经被撤回,不再参与 T39 对于 Promise 的提案,但是不妨碍社区对它的实现。axios 的 CancelToken 便是基于此实现的。
下面是一个简单的 CancelToken
let cancel |
上面这样子使用是对于单个请求而言,接下来我们考虑一种比较极端的情况。一个按钮,提交一次表单,然后我们在瞬时间连续按了 N 次,最坏的情况,按钮没有加防抖函数(Debounce),也没有使用按钮 Loading。那么,势必会向后台请求 N 次。
这个例子可能并不是很好,笔者再说一个特殊情况。
有一个查询请求,数据量比较大,需要 pending 比较久的时间,再这个过程中,用户通过切换 Tab 页重复查询了。那么 axios 的请求队列中就会有 2 个一模一样的请求在进行,实际上而言,我们需要的仅仅只是一个(本着先来先用的原则,可能只需要之前的那个就行)。这个时候我们为了不浪费网络资源,需要的就是掐掉那个一模一样的,但是是后面来的请求。
上面这种情况就需要我们在拦截器中进行拦截,拦截重复请求,然后进行 CancelToken。
先分析怎么实现,因为需要判断重复请求,所以需要思考怎么样的才算重复请求。笔者这边比较偷懒,判断 url + data。两者一模一样,即判定为重复请求
首先是在 request 拦截器里面进行部署 axios 的 CancelToken
const pending = [] // 请求队列 |
这边仅仅是一个例子,如果实际需求中提交是用 application/x-www-form-urlencoded 提交。那完全可以在 request 中使用 qs 模块,进行 qs.stringify 之后将序列化之后的请求体作为 uid,一举两得。
然后我们在构造一个移除重复请求的函数
/** |
最后一步,则是在 response 拦截器中,对于已经完成的请求进行移除
// http response 拦截器 |
当然上面代码有需要优化的地方(就留给大家啦),而 CancelToken 仅仅是在除去重复请求的方法的保底措施,实际中,大家还是尽量以 Loading,防抖函数为主。是否部署 CancelToken 应该是以具体的项目为准,切不可盲目部署,毕竟每一次请求之后都需要循环去 find 是否有重复请求,对于性能而言会有一点影响。