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 ...
随机推荐
- leetcode 27. 移除元素 【时间击败100.00%】【内存击败84.67%】
1 public int removeElement(int[] nums, int val) { 2 int last = nums.length - 1; 3 for (int i = 0; i ...
- drf从入门到飞升仙界 09
接口文档 # 1.前后端分离 - 后端:写接口 - 前端:根据接口写app,小程序,pc端 # 2.作为后端开发 - 我们应该清楚: ---> /api/v1/login/ ---> 登录 ...
- window批处理一键打开多个exe
使用批处理的start命令,格式为start /d "绝对路径" 目标exe名,记得路径和exe名间有个空格 @echo off start /d "E:\demo\&q ...
- Java流程控制之while循环详解
while循环 while循环 do...while循环 for循环 在Java5中引入了一种主要用于数组的增强型for循环 while循环 while循环是最基本的循环,它的结构为 while(布尔 ...
- Cloudflare.com设置域名URL转发
1.登录Cloudflare.com,将语言设置为简体中文,并选择需要设置URL转发的域名. 2.选择域名,需先对域名进行解析,解析地址随便填写,可以填写CloudFlare官方提供的DNS服务器地址 ...
- openwrt从gitee pull代码并编译go项目
安装ssh opkg update # openssh-keygen 可以用来生产密钥 opkg install openssh-keygen # 连接其他服务器 opkg install opens ...
- 062_Apex使用Assert
assert关键字用法简单,但是使用assert往往会让你陷入越来越深的陷阱中.应避免使用.总结了以下原因: 1.用assert代替if是陷阱之二.assert的判断和if语句差不多,但两者的作用 ...
- 通过python程序让MySQL利用binlog恢复误操作数据
MySQL利用binlog恢复误操作数据 在人工手动进行一些数据库写操作的时候(比方说数据订正),尤其是一些不可控的批量更新或删除,通常都建议备份后操作.不过不怕万一,就怕一万,有备无患总是好的.在线 ...
- holiday10
holiday10 ssh配置别名 每次输入 ssh -p port user@remote 时间久了都会觉得麻烦, 而 配置别名 可以让我们进一步偷懒,比如用 ssh mac 来代替上面一长串,那么 ...
- Windows MFC HTTP GET请求 函数流程
Windows MFC HTTP GET请求 函数流程 1 CString m_strHttpUrl(_T("http://10.200.80.86:8090/course/upload&q ...