有一个input输入发请求筛选员工的功能
由于前一次的请求耗时远大于后一次请求,导致页面渲染内容错误,本应该渲染最后一次的结果却被第一次请求的结果覆盖
有很多解决方案,但是大部分解决方案都有问题
1.防抖节流:可一定程度上缓解问题,但不能完全解决,请求时间过长还是会出现这个问题。
2.前后端配合,前台发请求时带上一个字段,后台返回结果时将该字段返回,前台判断只有最后一次请求时的数据为准,该方法能解决问题,但前后台都需要参与且代码量不小,维护成本高
3.利用观察者模式,将请求顺序入栈,然后按顺序出栈。此方法可以彻底解决问题,而且也不需要后台配合,但是性能损耗大,因为需要一直监听栈的变化,而且前端维护量大,有需要的地方都需要引入。
综上:目前最合适的解决方案如下
原理:相同请求在没有返回值之前,若再次调用则进行拦截并取消
(1)定义移除方法
// 先定义方法,用于移除重复请求
const pending = {};
const removePending = (key, isRequest = false) => {
if (pending[key] && isRequest) {
pending[key]("取消重复请求!");
}
if (pending[key]) {
delete pending[key];
}
}
(2)请求-响应拦截
import axios, { CancelToken } from 'axios';
const service = axios.create({
...
})
// 请求拦截
// 我这里key为 url + & + method, 可以根据项目需求自定义key键
// 每一个请求都为其创建一个key和CancelToken的实例
service.interceptors.request.use(
config => {
const key = config.url + '&' + config.method;
removePending(key, true);
config.cancelToken = new CancelToken((cancel) => {
pending[key] = cancel;
})
return config;
}
)
// 响应拦截
// 若在pending中存在,则会直接cancel请求
service.interceptors.response.use(
response => {
const key = response.config.url + '&' + response.config.method;
removePending(key);
return response;
},
error => {
console.log('err' + error) // for debug
}
)
(3)项目为vue,所以用的axios