用函数节流与函数防抖的目的,就是为了降低回调执行频率,节约计算机资源,提升用户体验。
- 节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
- 防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
一个经典的比喻:
想象每天上班大厦底下的电梯。把电梯完成一次运送,类比为一次函数的执行和响应
假设电梯有两种运行策略 debounce 和 throttle,超时设定为15秒,不考虑容量限制
电梯第一个人进来后,15秒后准时运送一次,这是节流;
电梯第一个人进来后,等待15秒。如果过程中又有人进来,15秒等待重新计时,直到15秒后开始运送,这是防抖。
节流
节流一般是用在滚动条滚动onscroll、鼠标移动onmousemove的函数,间隔一段时间执行一次,可以减少响应次数;
实现:设置一个标志位用于标记函数是否可以执行;
function scrollFn(e) {
console.log("请求接口", e.target.value);
}
// 节流
function throttle(fn) {
let flag = true; //默认执行完毕了
return function (e) {
if (!flag) {
//false时return,上次没有执行完,没有必要再执行
return;
}
flag = false; //改为没有执行
setTimeout(() => {
fn && fn(e)
flag = true; //执行完之后再改为true
}, 100);
};
}
const onscroll = throttle(scrollFn);
防抖
防抖一般是用来,用户输入有操作时,暂时不执行动作,等待没有新操作时,进行相应响应,例如input输入时搜索,可以等待用户输入完成后再发送请求;窗口大小resize。只需窗口调整完成后,计算窗口大小。防止重复渲染。
解决思路:
1.在第一次事件触发时,不立即执行函数,而是设定一个期限值;
2.若在期限值内,事件没有再次被触发,则执行函数;
若在期限值内,事件被再次触发,则清除当前计时器,重新开始记时。
function inputFn(e) {
console.log("请求接口", e.target.value);
}
// 防抖
function debounce(fn) {
let timer = null;
return function (e) {
if (timer) {
clearTimeout(timer);//触发了相同事件,取消当前计时,重新开始计时
}
timer = setTimeout(() => fn && fn(e), 1000);////第一次执行,开始一个计时器
};
}
// 输入完之后请求一次
document.getElementById("inputId").oninput = debounce(inputFn);