函数节流与函数防抖都是为了限制函数的执行次数,以优化函数触发频率过高导致的响应速度跟不上触发频率,出现延迟、假死或卡顿的现象。
一、定义
函数防抖:触发搞频率事件后n秒内函数只会执行一次,如果n秒内高频率事件再次被执行则重新计算时间
函数节流:高频率事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率
二、防抖(debounce)
1、应用场景
- search搜索联想,用户在不断的输入值时,用防抖来节约请求资源
- window触发resize的时候
- 不断的调整浏览器窗口大小会不断的触发这个事件,用防抖只会让其只触发一次
- 放置重复提交
- 表单验证
- 搜索框输入
2、实现方式
每次触发事件时设置一个延迟调用方法,并且取消之前的延时调用方法
<button id="debounce">点我防抖!</button>
$('#debounce').on('click', debounce());
function debounce() {
let timer; // 创建一个标记用来存放定时器的返回值
// 闭包
return function () {
// 每当用户输入的时候把前一个 setTimeout clear 掉
clearTimeout(timer);
// 然后又创建一个新的 setTimeout, 这样就能保证interval 间隔内如果时间持续触发,就不会执行 fn 函数
timer = setTimeout(() => {
// 需要防抖的操作...
console.log("防抖成功!");
}, 500);
}
}
3、缺点
如果事件在规定的时间间隔内被不断的触发,则调用方法会被不断的延迟
三、节流(throttle)
1、应用场景
- 鼠标连续不断的触发某个事件,在单位时间内只触发一次
- 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断。
- 在页面的无限加载下,需要用户在滚动页面时,每隔一段时间发送一次ajax请求,而不是用户在停下页面滚动的时候,再去请求。
- 懒加载、滚动加载、加载更多;
- 百度搜索框,搜索联想功能;
- 防止高频点击提交,防止表单重复提交;
2、实现方式
每次触发事件时,如果当前有等待执行的延时函数,则直接return (定时器/时间戳)
<button id="throttle">点我节流!</button>
$('#throttle').on('click', throttle());
function throttle(fn) {
let flag = true; // 通过闭包保存一个标记
// 闭包
return function () {
// 在函数开头判断标记是否为true,不为true则return
if (!flag) {
return;
}
// 立即设置为false
flag = false;
// 将外部传入的函数的执行放在setTimeout中
setTimeout(() => {
console.log("节流成功!");
// 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
// 当定时器没有执行的时候标记永远是false,在开头被return掉
flag = true;
}, 1000);
};
}
总结:节流的道理其实就是让函数执行一次后,在某个时间段内暂时失效,过了这个时间段后再重新激活。
四、防抖和节流的总结:
1. 防抖(debounce) 防抖是限制频率,多次出发一次执行。
2. 节流(throttle) 节流是限制次数,限制规定时间内执行次数
五、防抖和节流的区别
函数节流不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触发一次函数。