1.用途
节流和防抖本质都是优化高频率执行代码的一种手段,例如浏览器的resize、scroll、keypress、mousemove等事件在触发时,都会不断的调用绑定在事件上的回调函数,会极大地浪费资源,降低前端性能,为了优化性能,这时候就可以采用节流(throttle)和防抖(debounce)来减少调用频率。
定义
- 节流:n秒内只运行一次,若在n秒内重复触发,则只有一次生效
- 防抖:等待n秒后执行这件事情,如果在等待的n秒内重复触发,则重新计时
举例
- 节流:类似于游戏中的技能冷却,假设技能只能在10s内触发一次,当你使用了这个技能之后,在之后的10s内技能会进入冷却期,无法再次使用,只有等cd结束,才能再次使用。
- 防抖:类似于moba中的回城技能,假设当你开始读条回城时,此时会有一个10s的回城计时器。如果你不做操作,回城计时器10s计时结束后,便可以回城;但如果在这个10s期间,你如果打断了回城,那回城计时器的10s等待时间便会重新计时,直到10s后才能回城。
2.代码实现
节流
const throttle = (fn, delay) => {
let timer = null;
return (...args) => {
// 使用 null 作为判定条件,默认返回 false
if (timer) return;
// fn 写在 setTimeout 外是执行后等待 delay 才能再次触发,即先触发再等待
// fn 写在 setTimeout 内则是等待 delay 后才能执行,之后可以再次触;即先等待再触发
fn.call(undefined, ...args);
timer = setTimeout(() => {
timer = null;
}, delay);
};
};
防抖
const debounce = (fn, delay) => {
let timer = null;
return (...args) => {
if (timer !== null) {
clearTimeout(timer); // cd中再次调用 fn 时清空计时器
}
timer = setTimeout(() => {
fn.call(undefined, ...args); // delay 后调用 fn 并清空计时器
timer = null;
}, delay);
};
};
3.区别
相同点
- 通过使用
setTimeout实现 - 目的都是,降低回调执行频率。节省计算资源
不同点
- 函数防抖,在一段连续操作结束后,处理回调,利用
clearTimeout和setTimeout实现。函数节流,在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能 - 函数防抖关注一定时间连续触发的事件,只在最后执行一次,而函数节流一段时间内只执行一次
4.应用场景
节流
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能
- 验证码的发送按钮
防抖
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小
resize。只需窗口调整完成后,计算窗口大小。防止重复渲染