# 实现防止重复请求
对于测试人员来说,重复点击按钮进行测试的这个动作怎一个熟练了得,如果没对按钮做防止重复请求的操作,测试人员将喜提一个bug并内心深处肯定是。。。(好菜)所以对按钮进行防止重复请求操作非常重要。
# 黄铜
添加一个变量,判断是否点击了按钮,是的话再次点击直接return,否则触发请求
if (isLoading) return
isLoading = true
XXXApi.XXX().then(data => {
......
isLoading = false
}).catch(err => {
isLoading = false
})
# 白银
给按钮添加loading状态遮罩层,如el-button 添加 loading属性。多了loading动画,免了判断。
<el-button class="two-words" type="primary" :loading="isLoading" @click="handleQuery">查询</el-button>
isLoading = true
XXXApi.XXX().then(data => {
......
isLoading = false
}).catch(err => {
isLoading = false
})
# 铂金
从根源处解决防止重复请求,当请求未响应时,遇到相同请求不予操作。
VUE项目利用Axios实现好用的API层请求接口封装 (opens new window)
# 钻石
相对铂金的方式,解决了铂金的方式存在当响应较慢时,更改数据后再点击按钮后无做任何操作,导致提交的数据并非最新更改后的数据。因此还需要优化。
使用axios取消请求的方式,实现对相同请求,取消前面的请求。
上代码
// request.js
import axios from "@/api/axios"
import originalAxios from "axios"
const GLOBAL_REQUEST_OBJ = {}
function newRequest(name, params) {
return new Promise((resolve, reject) => {
if (GLOBAL_REQUEST_OBJ[name]) {
GLOBAL_REQUEST_OBJ[name].cancel(params.showLoading)
}
const CancelToken = originalAxios.CancelToken
GLOBAL_REQUEST_OBJ[name] = CancelToken.source()
Object.assign(params, {cancelToken: GLOBAL_REQUEST_OBJ[name].token})
axios(params).then(result => {
delete GLOBAL_REQUEST_OBJ[name]
resolve(result)
}).catch(err => {
reject(err)
})
})
}
["get", "post", "delete", "put", "patch"].forEach(type => {
newRequest[type] = (name, ...params) => {
let isShowLoading = false
if (params[1].params && (type === "get" || type === "delete") && !params[2]) {
isShowLoading = params[1].showLoading || false
} else {
isShowLoading = params[2].showLoading || false
}
return new Promise((resolve, reject) => {
if (GLOBAL_REQUEST_OBJ[name]) {
GLOBAL_REQUEST_OBJ[name].cancel(isShowLoading)
}
const CancelToken = originalAxios.CancelToken
GLOBAL_REQUEST_OBJ[name] = CancelToken.source()
// 第二个参数对象 存在 params且是 get 请求 或者 delete 请求, 无第三个参数 config
if (params[1].params && (type === "get" || type === "delete") && !params[2]) {
params[1].cancelToken = GLOBAL_REQUEST_OBJ[name].token
} else { // 配置config
Object.assign(params[2], {cancelToken: GLOBAL_REQUEST_OBJ[name].token})
}
axios[type].apply(this, params).then(result => {
delete GLOBAL_REQUEST_OBJ[name]
resolve(result)
}).catch(err => {
reject(err)
})
})
}
})
export const axiosRequest = newRequest
接口请求的地方使用
// common-api.js
import { axiosRequest } from "@/api/request"
import axios from "@/api/axios"
/**
* @description: get请求示例
* @param {*} data
* @param {*} config
* @return {*}
* @author: syx
*/
export function getDemo(data = {}, config = {}) {
const options = Object.assign({ params: data }, config)
return axiosRequest.get("commmonApi" + "getDemo", `/url`, options)
}
/**
* @description: post请求示例
* @param {*}
* @return {*}
* @author: syx
*/
export function postDemo(data = {}, config = {}) {
return axiosRequest.post("commmonApi" + "postDemo", "url", data, config)
}
/**
* @description: delete请求示例1
* @param {*}
* @return {*}
* @author: syx
*/
export function deleteDemo1(data = {}, config = {}) {
return axiosRequest.delete("commmonApi" + "deleteDemo1", "url", data, config)
}
/**
* @description: delete请求示例2
* @param {*} data
* @param {*} config
* @return {*}
* @author: syx
*/
export function deleteDemo2(data = {}, config = {}) {
const options = Object.assign({ params: data }, config)
return axiosRequest.delete("commmonApi" + "deleteDemo2", `/url`, options)
}
/**
* @description: put请求示例
* @param {*}
* @return {*}
* @author: syx
*/
export function putDemo(data = {}, config = {}) {
return axiosRequest.put("commmonApi" + "putDemo", "url", data, config)
}
/**
* @description: patch请求示例
* @param {*}
* @return {*}
* @author: syx
*/
export function patchDemo(data = {}, config = {}) {
return axiosRequest.patch("commmonApi" + "patchDemo", "url", data, config)
}
# 总结
对于黄铜和白银的方式,存在很多按钮时,需要定义多个变量,且项目中处处需要添加代码。
铂金和钻石则采用从根源处解决问题,无需添加代码判断,钻石解决了铂金存在的问题,如有更好的方式,欢迎指导。
此篇文章为axios请求优化其三,关于防止接口重复请求的优化,关注微信公众号【爆米花小布】不迷路。如有问题,可私信。