文章优化更新于2020-05-16 10:30,并将测试代码上传了github(https://github.com/Joseph244/preventRequestRepeat),欢迎指正!
1.自定义指令directive
import Vue from 'vue'
const preventReClick = Vue.directive('preventReClick', {
inserted: function(el, binding) {
el.addEventListener('click', () => {
if (!el.disabled) {
el.disabled = true
setTimeout(() => {
el.disabled = false
}, binding.value || 3000) // 传入绑定值就使用,默认3000毫秒内不可重复触发
}
})
}
})
export { preventReClick }
在main.js中引用
import preventReClick from './plugins/directives.js' //防多次点击,重复提交
在按钮上添加v-preventReClick
// 指定延迟1000ms
<el-button size="small" type="primary" @click="handleSave()" v-preventReClick="1000">保 存</el-button>
// 默认延迟时间3000
<el-button size="small" type="primary" @click="handleSave()" v-preventReClick>保 存</el-button>
2.请求队列与axios.CancelToken取消请求
补充知识点——Axios 的 cancel
可以使用 CancelToken.source
工厂方法创建 cancel token,像这样:
var CancelToken = axios.CancelToken;
var source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
还可以通过传递一个 executor 函数到 CancelToken
的构造函数来创建 cancel token:
var CancelToken = axios.CancelToken;
var cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
Note : 可以使用同一个 cancel token 取消多个请求
封装代码如下:
import Axios from 'axios'
const baseURL = 'http://rap2.taobao.org:38080/app/mock/238367/' // 后台baseUrl
const axios = Axios.create({
baseURL: baseURL,
timeout: 30000
})
const pending = [] // 声明一个数组用于存储每个ajax请求的队列
const cancelToken = Axios.CancelToken // 初始化取消请求的构造函数
let arr = [] // 区分是请求还是响应的头部
/** * @param {请求体信息} config * @param {直接执行的cancel函数,执行即可取消请求} f */
const removePending = (config, f) => {
arr = config.url.split(baseURL)
arr = arr[arr.length - 1]
// 每次请求存储在请求中队列的元素关键值,例如:一个地址为books/create的post请求处理之后为:"books/create&post"
const flagUrl = arr + '&' + config.method
// 当前请求存在队列中,取消第二次请求
if (pending.indexOf(flagUrl) !== -1) {
if (f) {
// f为实例化的cancelToken函数
f()
} else {
pending.splice(pending.indexOf(flagUrl), 1)
// cancelToken不存在,则从队列中删除该请求
}
} else {
// 当前请求不在队列中,就加进队列
if (f) {
pending.push(flagUrl)
}
}}
// 添加请求拦截器
axios.interceptors.request.use(
config => {
if (config.method === 'post') {
// 由于表单提交都使用post请求,此处只对post做处理;具体情况要结合业务需要
config.cancelToken = new cancelToken(c => {
removePending(config, c)
})
}
return config
}, error => {
return Promise.reject(error)
})
axios.interceptors.response.use(response => {
if (response.config.method === 'post') {
removePending(response.config)
}
})
export default axios
使用vue-cli做的完整测试代码见本人github: https://github.com/Joseph244/preventRequestRepeat
3.其他情况
原地址
- 要考虑并理解 success, complete, error, timeout 这些事件的区别,并注册正确的事件,一旦失误,功能将不再可用;
- 不可避免地比普通流程要要多注册一个 complete 事件;
- 恢复状态的代码很容易和不相干的代码混合在一起;
我推荐用主动查询状态的方式(A、B,jQuery 为例)或工具函数的方式(C、D)来去除重复操作,并提供一些例子作为参考:
A. 独占型提交
只允许同时存在一次提交操作,并且直到本次提交完成才能进行下一次提交。
module.submit = function() {
if (this.promise_.state() === 'pending') {
return
}
return this.promise_ = $.post('/api/save')
}
B. 贪婪型提交
无限制的提交,但是以最后一次操作为准;亦即需要尽快给出最后一次操作的反馈,而前面的操作结果并不重要。
module.submit = function() {
if (this.promise_.state() === 'pending') {
this.promise_.abort()
}
// todo
}
比如某些应用的条目中,有一些进行类似「喜欢」或「不喜欢」操作的二态按钮。如果按下后不立即给出反馈,用户的目光焦点就可能在那个按钮上停顿许久;如果按下时即时切换按钮的状态,再在程序上用 abort 来实现积极的提交,这样既能提高用户体验,还能降低服务器压力,皆大欢喜。
C. 节制型提交
无论提交如何频繁,任意两次有效提交的间隔时间必定会大于或等于某一时间间隔;即以一定频率提交。
module.submit = throttle(150, function() {
// todo
})
如果客户发送每隔100毫秒发送过来10次请求,此模块将只接收其中6个(每个在时间线上距离为150毫秒)进行处理。
这也是解决查询冲突的一种可选手段,比如以知乎草稿举例,仔细观察可以发现:
编辑器的 blur 事件会立即触发保存;
保存按钮的 click 事件也会立即触发保存;
但是存在一种情况会使这两个事件在数毫秒内连续发生——当焦点在编辑器内部,并且直接去点击保存按钮——这时用 throttle 来处理是可行的。
另外还有一些事件处理会很频繁地使用 throttle,如: resize、scroll、mousemove。
D. 懒惰型提交
任意两次提交的间隔时间,必须大于一个指定时间,才会促成有效提交;即不给休息不干活。
module.submit = debounce(150, function() {
// todo
})
还是以知乎草稿举例,当在编辑器内按下 ctrl + s 时,可以手动保存草稿;如果你连按,程序会表示不理解为什么你要连按,只有等你放弃连按,它才会继续。
今天的文章Vue工程化封装实践系列(二)[表单按钮重复提交,axios重复请求的处理方案]分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/16929.html