解决按钮重复点击问题?
在开发过程中,遇到过这样的场景 点击按钮,发送请求,在请求结束前,一个按钮可以重复点击,导致接口重复请求多次,请求堆积,轻则浪费服务器资源,重则业务逻辑错误、导致数据一致性问题,尤其接口涉及到写入操作(表单提交、订单创建)、用户体验感也下降。因此在网上看了些相关内容,并结合自己粗鄙了解,记录下面试回答的问题,欢迎批评指正
- 简单来讲,使用防抖
函数不会被直接执行,而是等触发后等待了设定的时间都没被触发才会被执行。
function debounce(func, delay) {
let timer = null;
return function(...args) {
if(timer) clearTimeout(timer);
// 重新设置定时器
timer = setTimeout(() => {
func.apply(this,args);
timer = null;
}, delay);
};
}
// 使用
const debouncedDubmit = debounce(submit, 300);
限制:如果接口响应时间过长,超过了防抖时间,那么仍可以多次触发请求过程
- 使用节流:
节流函数通过记录上次执行时间,确保在设定的时间间隔(如 1 秒)内,无论触发多少次点击,函数只会执行一次。并且在节流期间可以给用户视觉反馈,如按钮置灰、显示加载中loading..
function throttle (fn, interval) {
let lastTime = 0;
// 用于标记是否被禁用
let isDisabled = false;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval && !isDisabled) {
isDisabled = true;
fn.apply(this, args);
lastTime = now;
// 间隔时间后恢复可用状态
setTimeout(() => {
isDisabled = false;
}, interval);
}
}
}
这里如果要是使用loading的话,可以加一个延时,因为正常来讲,接口1s内都能返回,超过1s才显示loading
-
接口请求封装做处理
每次接口调用,对接口的url进行记录,直到请求结束才将其删除,在每次请求的时候,先检查记录中是否存在这个url请求,有则说明上次请求未完成,禁止请求,同时针对返回较快的接口使用节流,使其固定时间内只能发起1次请求。注意:如果存在同个接口不同参数调用处理。就需要在包含参数了。
其实就是在封装接口处做控制,限制重复提交,并且使用节流优化接口先响应过快的问题
const requestStatusMap = new Map();
/**
* 封装接口请求,防止重复请求,并对快速返回的接口节流
* @param {string} key - 请求唯一标识(如url+参数)
* @param {Function} apiFn - 实际请求函数,返回Promise
* @param {number} throttleTime - 节流时间(ms),默认300ms
* @returns {Promise}
*/
function requestWithThrottle(key, apiFn, throttleTime = 300) {
if (requestStatusMap.has(key)) {
// 已有请求进行中,直接返回同一个Promise
return requestStatusMap.get(key);
}
// 发起请求
const promise = new Promise((resolve, reject) => {
apiFn()
.then((res) => {
// 节流:快速返回的接口延迟resolve
const elapsed = Date.now() - (promise._startTime || Date.now());
const delay = Math.max(throttleTime - elapsed, 0);
setTimeout(() => {
resolve(res);
requestStatusMap.delete(key);
}, delay);
})
.catch((err) => {
requestStatusMap.delete(key);
reject(err);
});
});
promise._startTime = Date.now();
requestStatusMap.set(key, promise);
return promise;
- 前端锁机制
提交时设置一个标志,isSubmitting,提交完成后或失败进行重置
- 唯一标识校验
每次提交生成一个唯一Token,提交时候带上,后端进行校验token是否使用过,类似于防重复提交,最佳应该前后端结合使用,后端校验唯一token或者请求幂等性,确保统一数据只被处理一次 7. UI层面解决:
接口请求过程中自动显示遮罩层