JS使用axios取消请求 - Kaiqisan
JS使用axios取消请求
ヤッハロー、Kaiqisanすうう、一つふつうの学生プログラマである,这一次也是直面项目上遇到的问题。
这次内容有点多,如果您只是想复制代码的话,我做个目录,直接跳到目录找代码即可。
前端单方面违约取消请求,所以,这里的代码只有前端的事情。
官网写的取消法
/* a.js */
import axios from 'axios'
let CancelToken = axios.CancelToken
let source = CancelToken.source()
export default {
getReq() {
axios({
methods: 'get',
url: 'http://localhost:3000/testGet',
// 本地写了简易服务器,设置延时处理请求模拟网卡的情况,大家有能力的可以自己写一个服务器
cancelToken: source.token // 关键代码
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
},
cancelReq() {
source.cancel('do cancel')
source = CancelToken.source() // 重新规划
}
}
这些代码直接下载.vue .jsx文件中也可以,只要参数到位,找到合适的机会触发就可以了。
PS:上面的取消操作是AOE影响的,意思就是说它可以一次取消多次请求,如果一个人在短时间内发起多次请求,后端没来得及处理,让未处理的请求排起了队伍,一个取消操作就可以取消所有还未返回的请求。
///
现在我们来扒一下它的源码,康康这个过程是怎么样的呢!?
CancelToken = axios.CancelToken
首先针对这句话来展开研究。
我们在输出栏打开源码,看到的是以下内容
function CancelToken(executor) {
if (typeof executor !== 'function') { // 非法情况处理
throw new TypeError('executor must be a function.');
}
var resolvePromise;
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve; // 通过外部来影响这个异步函数的去向
});
var token = this;
executor(function cancel(message) {
if (token.reason) { // 如果已经取消了,就不再执行第二次'取消请求'
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason); // 成功取消请求,返回参数reason
});
}
/**
* Throws a `Cancel` if cancellation has been requested.
*/
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason; //
}
};
/**
* Returns an object that contains a new `CancelToken` and a function that, when called,
* cancels the `CancelToken`.
*/
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
module.exports = CancelToken;
然后是第二句话,source = CancelToken.source()
,它对于上面源码的最后一个函数,通过打印,我们可以看到这个CancelToken.source()
返回了一个对象,它有俩成员,一个是token异步函数(原型是Promise),一个是cancel方法。
然后基本的命名都OK了,接下来就可以正式投入使用了。
在请求中触发了cancel()方法之后,这个方法被执行(自己去上面源码找)
function cancel(message) {
if (token.reason) { // 如果已经取消了,就不再执行第二次'取消请求'
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason); // 成功取消请求,返回参数reason
}
然后触发resolvePromise,走then路线
if (config.cancelToken) { // 检测原生的请求里是否有cancelToken,如果没有就不执行下面的方法
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) { // 没有请求直接劝退
return;
}
request.abort(); // 原生的取消请求方法
reject(cancel); // 请求那边走catch路线,返回cancel参数
// 复位数据
request = null; // 清空请求
});
}
至于在取消请求之后再次调用CancelToken.source()
复位的问题,如果不复位的话,下次再发请求的话就会直接取消,因为此时的CancelToken凭证已经被触发,想要验证的话可以在请求取消前后查看CancelToken.source()
,我们会发现在请求取消后,它的token参数中多了一个reason属性。这就表示请求已经被取消。凭证是一次性的,如果发现凭证有reason属性,就表示需要取消请求。所以需要复位。
取消方法2
上面已经讲了原理,下面就不会再详细展开
/* a.js */
import axios from 'axios'
let CancelToken = axios.CancelToken
let cancel // 取消参数
export default {
getReq() {
axios({
methods: 'get',
url: 'http://localhost:3000/testGet',
// 本地写了简易服务器,设置延时处理请求模拟网卡的情况,大家有能力的可以自己写一个服务器
cancelToken: new CancelToken(function executor(c) {
cancel = c;
}) // 等同于上面的 source.token
}).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
},
cancelReq() {
cancel('do cancel')
}
}
PS:executor函数内的参数c为函数
function cancel(message) {
if (token.reason) { // 如果已经取消了,就不再执行第二次'取消请求'
return;
}
token.reason = new Cancel(message);
resolvePromise(token.reason); // 成功取消请求,返回参数reason
}
它只能拦截当前请求,无法拦截所有已经发出去的请求,所以在开发的时候请做好防滑操作!
更加高度的封装,使用axios.create之后的取消方法
/* 配置文件 */
import axios from 'axios'
// 创建axios实例
const service = axios.create({
baseURL: configJS.BASE_API,
})
// request拦截器
service.interceptors.request.use(
...........// 请求拦截
)
// respone拦截器
service.interceptors.response.use(
............
)
export default service
配置文件就正常创建
/* api仓库 */
import axios from 'axios'
import request from '@/utils/request' // axios配置文件
getInfo(data, that) {
return request({
url: 'xxxxxxxx', // 自己定
method: 'get', // 只适合get请求的取消
params: data, // 参数
cancelToken: new axios.CancelToken(function executor(c) {
that.source = c
})
})
},
/* 开始正式调用 */
exeGetInfo() {
api.getInfo({ id: 10 }, this).then(res => {
.........
}).catch(err => {
........
})
}
cancelQuest() {
if (typeof this.source === 'function') {
this.source('终止请求') //取消请求
}
},
后来,我就在思索这个中断请求的原理,本来以为是前端再次向后端发送一个拒收的请求,但是,我打开服务器之后,发现在取消请求的时候并没有再一次收到第二条请求,所以,我就怀疑是前端自己直接拒收后端发来的请求。
下面是我的后端node.js代码
/* index.js主入口文件 */
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const cors = require('cors');
let router = require('./routes/routers')
app.all('*', function(req, res, next) {
console.log(req.method);
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Headers', 'Content-type');
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,PATCH");
res.header('Access-Control-Max-Age', 1728000); //预请求缓存20天
next();
});
app.use(cors({
origin: ['http://localhost:8800'],
methods: ['GET', 'POST'],
allowHeader: ['Content-Type', 'Authorization']
}))
app.use(bodyParser.urlencoded({
extended: false
}))
app.use(bodyParser.json())
app.use(router)
app.listen(3000, () => {
console.log('服务器启动')
})
/* routers.js路由文件 */
const express = require('express')
const router = express.Router()
router.get('/testGet', (req, res) => {
setTimeout(() => { // 增加处理时间,便于测试setTimeout
console.log('gggggggggggggg');
res.json([ // 返回的信息
{
name: 'Kaiqisan',uid: 100
},
{
name: 'Tom',uid: 101
}
])
}, 3000)
})
module.exports = router
后来发现,即使我取消了请求,后端还是会向前端发送信息,那就是说我前端拒收之后后端发来什么,我都不会去理会,直接丢弃。在axios方法这里,直接走catch路线,报错完事,方法结束了。所以,以此类推,这个方法只能取消get请求,而不会取消post等其他需要后端对后台数据做出修改操作的请求,除非在触发取消操作的时候再次要求后端取消相关的操作。
总结
取消请求是很重要的方法,虽然不会减少后端的负担(服务器:我谢谢你!),但是,可以显著减少前端的内存消耗,更少的请求代表更少的捕获数据次数,也代表更少的无用数据渲染和赋值,也会适量减轻前端项目工程的复杂度,再配合防滑锁,完美!
本文地址:https://blog.csdn.net/qq_33933205/article/details/108127541