当用户频繁的与UI
界面操作交互时,例如:窗口调整
(触发resize),页面滚动
(触发scroll),按钮点击
(触发mousedown
),实时搜索
(触发keyup)等,可能导致界面卡顿、浏览器奔溃、页面空白等情况。
而解决这一问题的,正是函数节流与函数防抖。
函数节流
定义:
不管事件触发有多频繁,只会让一个函数在某个时间窗口内执行一次,若在时间窗口内再次触发,则重新计算时间。
应用场景:
常用于鼠标连续多次点击(click),鼠标连续移动(mousemove),窗口尺寸连续改动(resize),鼠标滚轮连续滚动(scroll)等。
原生代码实现:
js
/*
* @description 封装节流函数
* @param { method, duration} [method是事件处理函数,duration是延迟时间]
* @return 匿名函数
* 原理: 通过判断是否达到一定的时间来触发函数
*/
export default function throttle(method, duration) {
let timer = null;
let prevTime = new Date(); // 之前的时间
return function() {
const that = this;
const currentTime = new Date(); // 当前的时间
const resTime = currentTime - prevTime; // 时间戳
// 当前距离上次执行时间小于设置的时间间隔
if (resTime < duration) {
// 清除上次的定时器,取消上次调用的队列任务,重新设置定时器。这样就可以保证500毫秒秒内函数只会被触发一次,达到了函数节流的目的
if(timer) {
clearTimeout(timer);
};
timer = setTimeout(function() {
prevTime = currentTime;
method.apply(that, arguments);
}, duration);
} else {
// 当前距离上次执行的时间大于等于设置的时间时,直接执行函数
// 记录执行方法的时间
prevTime = currentTime;
method.apply(that, arguments);
};
};
};
第三方库实现
js
import throttle from 'lodash.throttle'; // 引入lodash.throttle库
throttle(handleThrottle, 500); // 将触发事件处理函数作为第一个参数传入,第二个参数为间隔的时间,这里是500毫秒
函数防抖
定义:
当函数被触发后,只有在上一次函数执行一段时间后,才会再次触发函数
应用场景:
常应用于输入框搜索联想查询,只有在用户停止键盘输入时,才发送Ajax请求。
元素代码实现:
js
/*
* @description 函数防抖
* @param { method, duration} [method是事件处理函数,duration是延迟时间]
* @return 匿名函数
* 原理:它是维护一个计时器,规定在duration时间后触发事件处理函数,这样一来,只有最后一次操作事件处理函数才被真正的触发
*/
export default function debounce(method, duration) {
let timer = null;
return function(){
const that = this;
// 在本次调用之间的一个间隔时间内若有方法在执行,则终止该方法的执行
if(timer) {
clearTimeout(timer);
};
// 开始执行本次调用
timer = setTimeout(function(){
method.apply(that, arguments);
}, duration)
}
}
第三方库实现
js
import debounce from 'lodash.debounce'; // 引入lodash.debounce库
debounce(handleDebounce, 500);; // 将触发事件处理函数作为第一个参数传入,第二个参数为间隔的时间,这里是500毫秒
节流与防抖小结
共同点
- 都是解决频繁操作触发事件处理函数,引起页面卡顿,不流畅等性能问题
- 都是通过设置延时器逻辑来提升性能,减少事件处理函数触发。
不同点
函数节流,间隔时间内执行事件处理函数,而函数防抖,一定时间间隔内只执行最后一次操作。
接口防重
除了节流和防抖,还有一种更为严格的防止重复提交,即前端在向后端进行数据提交的时候,必须要等到第一次提交的接口返回结果后,才能进行下一步操作,而不是像节流和防抖那样,规定一定时间。
一般来说,第三方UI组件库中的button按钮中都自带loading效果,我们只要控制loading开启关闭的时间即可达到此需求。
但是,有些时候,UI设计的按钮样式不适合放loading的时候,我们应该如何处理呢?
用flag标志 + toast提示, 伪代码如下:
js
let sumitFlag = false;
const submit = () => {
if(!sumitFlag) {
sumitFlag = true;
//业务逻辑
} else {
ElMessage.warning(`请不要重复提交`);
};
};