Ajax请求等待期间按方法阻断重复操作的最佳实践问询
优化Ajax请求重复触发的方案:避免全局阻塞
单一的working全局标志确实会导致所有操作互相阻塞,完全没必要让“点赞”和“保存”这类独立操作互相等待。我们可以给每个独立操作维护自己的状态锁,或者用更灵活的方式管理请求状态,下面是几种实用的优化方案:
方案1:为每个操作单独设置状态变量
最直接的方式就是给每个需要防重复点击的操作分配独立的状态变量,这样不同操作之间的状态互不影响。
修改后的代码示例:
export default { data: function() { return { // 每个操作对应自己的状态锁 isProcessingA: false, isProcessingB: false } }, methods: { respondToClickA: function() { if(!this.isProcessingA) { this.isProcessingA = true; axios.get('/ajax') .then(function(response){ // 处理响应逻辑 }) .finally(() => { // 无论成功失败都重置状态 this.isProcessingA = false; }); } }, respondToClickB: function() { if(!this.isProcessingB) { this.isProcessingB = true; axios.get('/ajax') .then(function(response){ // 处理响应逻辑 }) .finally(() => { this.isProcessingB = false; }); } } } }
优点:简单直观,适合操作数量较少的组件;缺点:如果组件内操作很多,会导致data里的状态变量越来越多,略显冗余。
方案2:用对象统一管理所有操作的状态
如果组件内有多个需要防重复的操作,可以用一个对象来集中管理所有操作的状态,这样扩展性更好,不用每次加新操作都在data里新增变量。
修改后的代码示例:
export default { data: function() { return { // 键为操作标识,值为是否正在处理 workingStates: { clickA: false, clickB: false } } }, methods: { respondToClickA: function() { const actionKey = 'clickA'; if(!this.workingStates[actionKey]) { this.workingStates[actionKey] = true; axios.get('/ajax') .then(function(response){ // 处理响应逻辑 }) .finally(() => { this.workingStates[actionKey] = false; }); } }, respondToClickB: function() { const actionKey = 'clickB'; if(!this.workingStates[actionKey]) { this.workingStates[actionKey] = true; axios.get('/ajax') .then(function(response){ // 处理响应逻辑 }) .finally(() => { this.workingStates[actionKey] = false; }); } } } }
优点:状态集中管理,新增操作只需在workingStates里加键,或者甚至可以动态添加;缺点:需要为每个操作定义唯一的标识键,要注意命名规范。
方案3:封装通用的防重复请求工具函数
为了避免重复编写状态判断和重置的代码,可以封装一个通用函数,把状态管理和请求执行的逻辑抽离出来,让业务方法更简洁。
修改后的代码示例:
export default { data: function() { return { workingStates: {} } }, methods: { // 通用工具函数:处理操作的状态锁和请求执行 async withLoading(actionKey, requestFn) { // 如果该操作正在处理,直接返回 if (this.workingStates[actionKey]) return; // 标记为正在处理 this.workingStates[actionKey] = true; try { // 执行请求 const response = await requestFn(); return response; } catch (error) { // 可以在这里统一处理请求错误 throw error; } finally { // 无论成功失败,重置状态 this.workingStates[actionKey] = false; } }, // 业务方法A respondToClickA: function() { this.withLoading('clickA', () => axios.get('/ajax')) .then(response => { // 处理响应逻辑 }) .catch(error => { // 处理错误 }); }, // 业务方法B respondToClickB: function() { this.withLoading('clickB', () => axios.get('/ajax')) .then(response => { // 处理响应逻辑 }) .catch(error => { // 处理错误 }); } } }
优点:代码复用性高,业务方法只需要关注请求和响应处理,状态管理逻辑统一维护;缺点:需要额外封装工具函数,适合操作较多的场景。
进阶方案:结合Axios CancelToken取消重复请求
如果希望同一操作的重复点击直接取消之前未完成的请求(而不是阻止新请求),可以用Axios的CancelToken功能,这在用户快速点击同一按钮时很实用。
代码示例:
export default { data: function() { return { // 存储每个操作的CancelToken源 cancelSources: {} } }, methods: { respondToClickA: function() { const actionKey = 'clickA'; // 如果存在未完成的请求,先取消它 if (this.cancelSources[actionKey]) { this.cancelSources[actionKey].cancel('用户重复点击,取消之前的请求'); } // 创建新的CancelToken源 this.cancelSources[actionKey] = axios.CancelToken.source(); axios.get('/ajax', { cancelToken: this.cancelSources[actionKey].token }) .then(response => { // 处理响应逻辑 }) .catch(error => { // 判断是否是主动取消的请求 if (!axios.isCancel(error)) { // 处理其他错误 } }) .finally(() => { // 清空CancelToken源 this.cancelSources[actionKey] = null; }); }, respondToClickB: function() { const actionKey = 'clickB'; if (this.cancelSources[actionKey]) { this.cancelSources[actionKey].cancel('用户重复点击,取消之前的请求'); } this.cancelSources[actionKey] = axios.CancelToken.source(); axios.get('/ajax', { cancelToken: this.cancelSources[actionKey].token }) .then(response => { // 处理响应逻辑 }) .catch(error => { if (!axios.isCancel(error)) { // 处理其他错误 } }) .finally(() => { this.cancelSources[actionKey] = null; }); } } }
优点:可以避免同一请求多次发送到服务器,减少服务器压力;缺点:逻辑稍复杂,适合对性能要求较高的场景。
内容的提问来源于stack exchange,提问作者Ernest Melville
相关产品推荐
相关产品推荐

