axios的cancelToken
核心代码
import axios from 'axios'
// Base64可自行安装依赖或实现
import Base64 from './Base64'
class PendingPromiseStorage {
constructor() {
this._data = new Map()
}
setItem(payload) {
let { uid, item } = payload
this._data.set(uid, item)
}
getItem(uid) {
return this._data.get(uid)
}
removeItem(uid) {
this._data.delete(uid)
}
hasItem(uid) {
return this._data.has(uid)
}
cancelBefore(config) {
let { uid, url } = config
if (!this.hasItem(uid)) {
return
}
let item = this.getItem(uid)
let msg = `axios cancel (before cancel) ${url}`
item.cancel(msg)
this.removeItem(uid)
}
cancelAfter(config, cancel) {
let { uid, url } = config
if (!this.hasItem(uid)) {
return
}
let item = this.getItem(uid)
let msg = `axios cancel (after cancel) ${url}`
if (cancel !== item.cancel) {
setTimeout(() => {// 想看浏览器Network有记录,启用延迟
cancel(msg)
})
}
}
}
PendingPromiseStorage.getPendingUID = (config) => {
return Base64.encode(`${config.url}${config.method}${JSON.stringify(config.params)}${typeof config.data === 'string' ? config.data : JSON.stringify(config.data)}`)
}
const pendingPromiseStorage = new PendingPromiseStorage()
const interceptors = {
request: {
success(config) {
console.log('cancelToken:', config.cancelToken)
if (Object.hasOwnProperty.call(config, 'cancelToken')
&& (config.cancelToken === 'before' || config.cancelToken === 'after')
) {
let cancelToken = config.cancelToken
let uid = config.uid = PendingPromiseStorage.getPendingUID(config)
if (cancelToken === 'before') {
pendingPromiseStorage.cancelBefore(config)
}
let cancel = null
config.cancelToken = new axios.CancelToken(c => {
cancel = c
let item = {
uid,
createTime: Date.now(),
cancelToken,
cancel: c
}
if (
(cancelToken === 'before')
|| (cancelToken === 'after' && !pendingPromiseStorage.hasItem(uid))
) {
pendingPromiseStorage.setItem({ uid, item })
}
})
if (cancelToken === 'after') {
pendingPromiseStorage.cancelAfter(config, cancel)
}
}
return config
},
failed(error) {
let { config = {} } = error
pendingPromiseStorage.removeItem(config.uid)
return Promise.reject(error)
}
},
response: {
success(response) {
let { config } = response
pendingPromiseStorage.removeItem(config.uid)
return response
},
failed(error) {
let { config = {} } = error
pendingPromiseStorage.removeItem(config.uid)
return Promise.reject(error)
}
}
}
class Request extends axios.create {
constructor(config) {
super(config)
this.interceptors.request.use(interceptors.request.success, interceptors.request.failed)
this.interceptors.response.use(interceptors.response.success, interceptors.response.failed)
}
}
const instanceInterceptors = {
request: {
success(config) {
// TODO
return config
},
failed(error) {
return Promise.reject(error)
}
},
response: {
success(config) {
// TODO
return config
},
failed(error) {
return Promise.reject(error)
}
}
}
let instance = new Request({
name: 'Test-cancelToken',
baseURL: '/dev-api/',
timeout: 10000
})
instance.interceptors.request.use(instanceInterceptors.request.success, instanceInterceptors.request.failed)
instance.interceptors.response.use(instanceInterceptors.response.success, instanceInterceptors.response.failed)
export default instance
使用代码
export default {
methods: {
login() {
return request({
url: '/user/login',
method: 'post',
data: {
username: 'admin',
},
cancelToken: 'before'
// cancelToken: 'after'
})
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
}
}
}
// axios/lib/cancel/CancelToken.js
'use strict';
var Cancel = require('./Cancel');
function CancelToken(executor) {
if (typeof executor !== 'function') {
throw new TypeError('executor must be a function.');
}
/**
* 定义一个将来能执行取消请求的promise对象,当这个promise的状态为完成时(fullfilled),
* 就会触发取消请求的操作(执行then函数)。而执行resolve就能将promise的状态置为完成状态。
* 这里把resolve赋值给resolvePromise,就是为了在这个promise外能执行resolve而改变这个promise的状态
* 注意这个promise对象被赋值给CancelToken实例的属性promise,将来定义then函数就是通过这个属性得到promise
*/
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
/**
* 将CancelToken实例赋值给token
* 执行executor函数,将cancel方法传入executor,
* cancel方法可调用resolvePromise方法,即触发取消请求的操作
*/
var token = this;
executor(function cancel(message) {
if (token.reason) {
// 取消已响应 返回
return;
}
token.reason = new Cancel(message);
// 这里执行的就是promise的resolve方法,改变状态
resolvePromise(token.reason);
});
}
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason;
}
};
// 这里可以看清楚source函数的真面目
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
// c 就是CancelToken中给executor传入的cancel方法
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
module.exports = CancelToken;
// axios/lib/adapters/xhr.js
// 创建XHR对象
var request = new XMLHttpRequest()
// 模拟当前ajax请求
request.open(config.method.toUpperCase(), buildURL(config.url, config.params, config.paramsSerializer), true)
// 定义取消请求promise对象的then函数
if (config.cancelToken) { // 如果配置了cancelToken属性
// 当promise为完成态时,这个then函数执行,即执行取消请求
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
// 取消ajax请求
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
当使用new axios.cancelToken((c) => xx = c) 这里就是把一个执行函数放进去,然后在cancelToken中会new一个Promise 把promise的resolve丢到外面,然后再执行前面传进来的函数,我们传进来的函数中写一个参数就是c 这个c就是用来取消的,当c里面就是把这个resolve执行 执行了就会触发 promise的then 在then中使用xmlhttprequest.abort()的方法中断这个请求。
axios的cancelToken的更多相关文章
- axios 之cancelToken原理以及使用
看axios文档的时候发现cancelToken这个东东,这个是用来取消ajax请求的,一般原生的话用的是abort()这个方法.看到这玩意的第一感觉是用起来有点麻烦,但是看了内部实现,发现还是比较有 ...
- axios二次封装的几种方法
一.用Class方法 import axios from "axios"; declare var Promise: any; export class Request { sta ...
- vue自动完成搜索功能的数据请求处理
在现在的互联网世界里,自动完成的搜索功能是一个很常见的功能.比如百度.搜狗.360搜索 ... 功能描述一下大概是这个样子的:有一个搜索框,用户在里面输入要查询的条件,系统会“智能”判断用户输完了,然 ...
- vue+elementui搭建后台管理界面(7 vuex和mockjs的使用)
将权限管理应用到系统,首先做好登录, 点击登录按钮后,触发以下动作 vuex 中的 login 动作,设置 cookie vuex 中的 getuserinfo , 获取权限.用户名.头像等 由于目前 ...
- axios 重复点击利用CancelToken阻止请求多次发送
import axios from 'axios'; axios.defaults.timeout = 5000; axios.defaults.baseURL =''; let pending = ...
- axios全攻略
随着 vuejs 作者尤雨溪发布消息,不再继续维护vue-resource,并推荐大家使用 axios 开始,axios 被越来越多的人所了解.本来想在网上找找详细攻略,突然发现,axios 的官方文 ...
- vue使用Axios做ajax请求
vue2.0之后,就不再对vue-resource更新,而是推荐使用axios 1. 安装 axios $ npm install axios 或 $ bower install axios 2. 在 ...
- HTTP库Axios
前面的话 本文将详细介绍HTTP库Axios 概述 Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中 [安装] 在Vue中使用,最好安装两个模块axios ...
- axios配合vue+webpack使用
1.安装引用: cnpm install axios --save-dev 2.在组件中引入: import axios from 'axios'; 3.使用示例: 执行GET请求: // 为给定 I ...
- 前端MVC Vue2学习总结(六)——axios与跨域HTTP请求、Lodash工具库
一.axios Vue更新到2.0之后宣告不再对vue-resource更新,推荐使用axios,axios是一个用于客户端与服务器通信的组件,axios 是一个基于Promise 用于浏览器和 no ...
随机推荐
- MogDB 学习笔记之 -- PITR恢复
# 概念描述## 背景信息当数据库崩溃或希望回退到数据库之前的某一状态时,MogDB的即时恢复功能(Point-In-Time Recovery,简称PITR)可以支持恢复到备份归档数据之后的任意时间 ...
- centos7 yum安装配置Lnmp和负载配置
首先配置防火墙CentOS 7.0默认使用的是firewall作为防火墙1.关闭firewall: systemctl stop firewalld.service #停止firewallsystem ...
- 91、mysql批量删除表
## 存储过程实现 drop PROCEDURE if EXISTS rush; create PROCEDURE rush() BEGIN ## 创建临时表,插入快照数据 drop table if ...
- string转JSONObject顺序不变和 往map放数据按顺序
JSONObject field = JSONObject.parseObject(fieldStr,Feature.OrderedField); Map<String,String> m ...
- nginx代理出现上传文件过大解决办法
1.错误描述 2.错误原因 1.上传文件时,利用localhost访问系统,不会出现这个问题:用域名访问这个系统时,出现这个问题,提示是:请求实体太大 由于Nginx反向代理服务器client_max ...
- Qt中QGraphicsScene和QraphicsView显示坐标问题解决
相信打开这个界面的你,一定遇到了这两玩意儿设置完坐标发现对不上的问题...查询Qt官方文档后发现: 网上搜索了一番,基本上这个坐标系就是长酱紫: 所以加上这行代码就行了: ui->graphic ...
- linux 设置开机自动挂载文件系统
一./etc/ 下增加rc.local文件(ubuntu默认没有这个文件) kuaibang@face:~$ sudo touch rc.local 二.安装NFS客户端 a.如果您使用CentOS. ...
- 5. Python 函数
函数:(方法.功能) 作用:1.提高代码的复用性,2.让代码更简洁 函数命名方法 函数不调用是不会被执行的 def calc(a,b): #形参 #位置参数,必填,否则报错 res = a ...
- Java-String常用API
返回值类型 方法 用途 备注 char charAt(int index) 返回 char指定索引处的值. int compareTo(String anotherString) 按字典顺序比较两 ...
- Mac 卸载 Anaconda3
终端安装anaconda-clean conda install anaconda-clean 删除所有与 Anaconda 有关的文件与目录 anaconda-clean --yes 第 2 步中的 ...