使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式
0. 系列文章
1.使用Typescript重构axios(一)——写在最前面
2.使用Typescript重构axios(二)——项目起手,跑通流程
3.使用Typescript重构axios(三)——实现基础功能:处理get请求url参数
4.使用Typescript重构axios(四)——实现基础功能:处理post请求参数
5.使用Typescript重构axios(五)——实现基础功能:处理请求的header
6.使用Typescript重构axios(六)——实现基础功能:获取响应数据
7.使用Typescript重构axios(七)——实现基础功能:处理响应header
8.使用Typescript重构axios(八)——实现基础功能:处理响应data
9.使用Typescript重构axios(九)——异常处理:基础版
10.使用Typescript重构axios(十)——异常处理:增强版
11.使用Typescript重构axios(十一)——接口扩展
12.使用Typescript重构axios(十二)——增加参数
13.使用Typescript重构axios(十三)——让响应数据支持泛型
14.使用Typescript重构axios(十四)——实现拦截器
15.使用Typescript重构axios(十五)——默认配置
16.使用Typescript重构axios(十六)——请求和响应数据配置化
17.使用Typescript重构axios(十七)——增加axios.create
18.使用Typescript重构axios(十八)——请求取消功能:总体思路
19.使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式
20.使用Typescript重构axios(二十)——请求取消功能:实现第一种使用方式
21.使用Typescript重构axios(二十一)——请求取消功能:添加axios.isCancel接口
22.使用Typescript重构axios(二十二)——请求取消功能:收尾
23.使用Typescript重构axios(二十三)——添加withCredentials属性
24.使用Typescript重构axios(二十四)——防御XSRF攻击
25.使用Typescript重构axios(二十五)——文件上传下载进度监控
26.使用Typescript重构axios(二十六)——添加HTTP授权auth属性
27.使用Typescript重构axios(二十七)——添加请求状态码合法性校验
28.使用Typescript重构axios(二十八)——自定义序列化请求参数
29.使用Typescript重构axios(二十九)——添加baseURL
30.使用Typescript重构axios(三十)——添加axios.getUri方法
31.使用Typescript重构axios(三十一)——添加axios.all和axios.spread方法
32.使用Typescript重构axios(三十二)——写在最后面(总结)
1. 前言
通过上篇文章分析,我们知道:
- 请求配置对象中有一个请求取消令牌
cancelToken属性,该属性对应一个取消请求的触发函数; - 当在请求外部调用了该触发函数,表示此时需要取消请求了,那么我们此时调用
XMLHttpRequest对象上的abort()方法将请求取消即可。 axios混合对象上又多了一个静态接口CancelToken;CancelToken接口是一个类;CancelToken类的构造函数接收一个函数作为参数;- 并且这个参数函数也接收一个取消函数作为参数;
接下来,我们就基于以上这些信息来实现取消请求的第二种使用方式。
2. 定义接口类型
在创建CancelToken类之前,我们先在src/types/index.ts中定义一下相关的接口类型。
CancelToken类的实例对象接口类型CancelToken类的实例对象包含两个参数:一个必选参数是promise,类型是Promise<string>,因为它要接收字符串类型的取消原因作为参数;另一个是可选参数取消原因reason,类型是string。export interface CancelToken {
promise:Promise<string>
reason?:string
}
CancelToken类的构造函数的参数类型因为
CancelToken类的构造函数接收一个函数作为参数,因此,我们也需要定义一个该参数函数的类型。该参数函数又接收一个取消函数作为参数,它的类型是Cancelerexport interface CancelExecutor {
(cancel: Canceler): void
}
取消函数类型
Canceler取消函数接收错误原因
message作为参数。export interface Canceler {
(message?: string): void
}
修改
AxiosRequestConfig既然请求配置对象上多了一个
cancelToken属性,那当然需要再请求配置对象的接口类型定义上添加该属性。export interface AxiosRequestConfig {
// ...
cancelToken?:CancelToken
// ...
}
3. 创建CancelToken类
接口定义好之后,我们就可以来创建CancelToken类了,我们在src下新建cancel目录,并在该目录下创建CancelToken.ts,在该文件内创建CancelToken类,如下:
import { CancelExecutor } from "../types";
interface ResolvePromise {
(reason?: string): void;
}
export default class CancelToken {
promise: Promise<string>;
reason?: string;
constructor(executor: CancelExecutor) {
let resolvePromise: ResolvePromise;
this.promise = new Promise<string>(resolve => {
resolvePromise = resolve;
});
executor(message => {
if (this.reason) {
return;
}
this.reason = message;
resolvePromise(this.reason);
});
}
}
代码说明:
在
CancelToken构造函数内部,首先实例化了一个pending状态的 Promise 对象,然后用一个resolvePromise变量指向resolve函数。接着执行
executor函数,该函数接收的参数是:cancel函数,即:message => {
if (this.reason) {
return;
}
this.reason = message;
resolvePromise(this.reason);
}
cancel 函数就是将来的请求取消触发函数,当外部调用了 cancel 函数,在 cancel 函数内部,会调用 resolvePromise 把 Promise 对象从 pending 状态变为 resolved 状态。
4. 实现请求取消逻辑
上篇文章说过,实现请求取消实际上是调用了XMLHttpRequest对象上的abort()方法,在本项目中,能接触到XMLHttpRequest对象的就只有在src/core/xhr.ts中的请求核心函数xhr()内了,所以我们需要在该函数中实现请求取消的逻辑,并且请求取消指的是发出请求后取消,所以我们需要把这段逻辑实现在xhr()函数内的request.send()之后,如下:
const {
// ...
cancelToken
} = config;
// ...
// 3.发送请求
request.send(data);
if (cancelToken){
cancelToken.promise.then(reason => {
request.abort();
reject(reason)
})
}
// ...
代码说明:
- 首先判断用户是否配置的
cancelToken,如果没有配置,表示没有取消请求这项需求; - 如果配置了
cancelToken,并且当外部调用了请求取消触发函数,此时cancelToken.promise会变成resolved状态,然后就会执行then函数,在then函数内部调用XMLHttpRequest对象上的abort()方法取消请求。
OK,请求取消的逻辑就已经实现完了,接下来我们为axios混合对象添加CancelToken静态接口。
5. 添加CancelToken接口
给axios混合对象添加接口非常简单,我们已经添加过好几回了,我们仿照上次添加create接口那样,首先在src/types/index.ts中的axios混合对象接口定义中添加CancelToken,如下:
export interface CancelTokenStatic {
new(executor: CancelExecutor): CancelToken
}
export interface AxiosStatic extends AxiosInstance {
create(config?: AxiosRequestConfig): AxiosInstance;
CancelToken:CancelTokenStatic
}
由于CancelToken是一个类,我们还要为这个类定义一个类类型接口CancelTokenStatic,该接口里面有一个构造函数接口。
添加好接口类型以后,我们就可以在src/axios.ts中给axios混合对象添加CancelToken接口了,如下:
import CancelToken from "./cancel/CancelToken";
axios.CancelToken = CancelToken
OK,到此为止,官方axios取消请求的第二种使用方式就实现好了,在做demo之前,我们先来梳理一下整个流程。
6. 使用流程梳理
我们使用如下方式取消请求时,代码内部的流程都是怎样的,我们现在就来梳理下。
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
// executor函数接收一个取消函数作为参数
cancel = c;
})
});
cancel('Operation canceled by the user.');
流程梳理:
用户为请求配置了
cancelToken属性,该属性的属性值是CancelToken类的实例。实例化
CancelToken类时,会执行类的构造函数,我们为构造函数传入了一个executor函数,如下:function executor(c) {
// An executor function receives a cancel function as a parameter
// executor函数接收一个取消函数作为参数
cancel = c;
}
该函数接收一个参数,并把这个参数赋给了变量
cancel;在构造函数内部,首先实例化了一个
pending状态的 Promise 对象,然后用一个resolvePromise变量指向resolve函数。接着执行了传入的
executor函数,在执行executor函数的时候为其传入了一个参数,该参数如下:message => {
if (this.reason) {
return;
}
this.reason = message;
resolvePromise(this.reason);
}
执行了
executor函数,该函数会把这个参数赋给变量cancel,即变量cancel为:let cancel = message => {
if (this.reason) {
return;
}
this.reason = message;
resolvePromise(this.reason);
}
变量
cancel就是将来的请求取消触发函数,当外部取消请求时就会调用cancel函数,在cancel函数内部,会调用resolvePromise把Promise对象从pending状态变为resolved状态,也就是说把CancelToken类中的this.promise变成了resolved状态。而请求配置对象中的
cancelToken属性是CancelToken类的实例对象,那么它自然能够访问到类里面的promise属性,当该属性的状态变成resolved时,表明有人在外面调用了cancel函数,此时它就通过cancelToken.promise.then(reason => {
request.abort();
reject(reason)
})
来取消请求。
如果没有人调用
cancel函数,那么cancelToken.promise的状态就一直是pendding,就不能调用then方法,就不能取消请求。
以上就是代码的整个运行流程。接下来我们就来编写demo来测试以上流程是否正确。
7. demo编写
在 examples 目录下创建 cancel目录,在 cancel目录下创建 index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>cancel demo</title>
</head>
<body>
<script src="/__build__/cancel.js"></script>
</body>
</html>
接着再创建 app.ts 作为入口文件:
import axios from "../../src/axios";
import { Canceler } from "../../src/types";
const CancelToken = axios.CancelToken;
let cancel: Canceler;
axios.get("/api/cancel", {
cancelToken: new CancelToken(c => {
cancel = c;
})
})
.catch(function(e) {
console.log(e);
});
setTimeout(() => {
cancel("Operation canceled by the user");
}, 1000);
接着在 server/server.js 添加新的接口路由:
// 取消请求
router.get("/api/cancel", function(req, res) {
setTimeout(() => {
res.json({
msg: `hello world`
});
}, 3000);
});
我们设置响应在发出收到请求3秒后再响应,而在请求中,我们配置的是请求发出后1秒就取消请求,从而验证是否能够取消请求。
最后在根目录下的index.html中加上启动该demo的入口:
<li><a href="examples/cancel">cancel</a></li>
OK,我们在命令行中执行:
# 同时开启客户端和服务端
npm run server | npm start
接着我们打开 chrome 浏览器,访问 http://localhost:8000/ 即可访问我们的 demo 了,我们点击 cancel,通过F12的 network 部分我们可以看到:请求发出一秒后请求状态变成canceled,表明请求已经被成功取消了。

然后我们将demo中的取消请求触发函数注释,
//setTimeout(() => {
// cancel("Operation canceled by the user");
//}, 1000);
再发送请求,我们看到3秒后请求又可以正常得到响应了。

OK,取消请求的第二种使用方式就已经实现完毕了。
(完)
使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式的更多相关文章
- 使用Typescript重构axios(十八)——请求取消功能:总体思路
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(二十一)——请求取消功能:添加axios.isCancel接口
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(十六)——请求和响应数据配置化
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(二十二)——请求取消功能:收尾
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(十)——异常处理:增强版
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(十二)——增加参数
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(十四)——实现拦截器
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(十五)——默认配置
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- 使用Typescript重构axios(二十)——请求取消功能:实现第一种使用方式
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
随机推荐
- Flutter 错误捕获的正确姿势
背景 我们知道,在软件开发过程中,错误和异常总是在所难免. 不管是客户端的逻辑错误导致的,还是服务器的数据问题导致的,只要出现了异常,我们都需要一个机制来通知我们去处理. 在 APP 的开发过程中,我 ...
- 使用lombok中的log
idea中安装lombok插件 引入lombok依赖 <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> ...
- Tomcat7.0.40注册到服务启动报错error Code 1 +connector attribute sslcertificateFile must be defined when using ssl with apr
Tomcat7.0.40 注册到服务启动遇到以下几个问题: 1.启动报错errorCode1 查看日志如下图: 解决办法: 这个是因为我的jdk版本问题,因为电脑是64位,安装的jdk是32位的所以会 ...
- html5视频常用API接口
一.虽然有的属性是boolean类型,但仍旧建议按照XHTML书写(属性名=”属性值”)格式,避免出现错误 (下面加粗的属性为常用属性) 属性 值 功能描述 controls controls 是否显 ...
- Android仿美团地址选择
最近做了这个功能,分享一下,用的是百度地图api,和美团外卖的地址选择界面差不多,也就是可以搜索或者滑动地图展示地址列表给用户选择,看下效果图先. 文章重点 1.展示地图并定位到“我”的位置2.滑动地 ...
- 写在Python学习前
Python是一门非常有意思的语言,不需要太多的语言基础,就可以实现自己想要的操作.许多非计算机专业的学生都可以利用词云分析.分词.画图等实现自己想要的东西.学习Python和学习其他语言一样,需要耐 ...
- SecureCRT连接虚拟机下的CentOS7
1.首先在VMWare下配置CentOS为桥接模式: 2.查看本机ip: 3.ip addr查看centos的mac地址: 4.在root权限下修改/etc/sysconfig/network-scr ...
- luoguP1006 传纸条
题目描述 Description 小渊和小轩是好朋友也是同班同学,他们在一起总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个 m" role="presentation& ...
- win10系统 plsql developer启动慢
win10系统plsql启动慢一般原因是plsql打印设置的问题,若默认打印机设置为网络上某一位置的打印机,则plsql启动时会去寻找该打印机,导致启动很慢. 解决办法1 直接禁止print spoo ...
- AppBoxFuture: 服务模型的在线调试与性能监测
框架内的服务模型(ServiceModel)用于处理各类业务逻辑(如最简单的CRUD操作),在设计时以类似于伪代码的形式存在,发布时后端会通过Roslyn转换并编译为运行时代码.为了方便开发者作者 ...