防抖:等你干完活,延迟执行一次;节流:每隔一段时间,最多只能执行一次 。
生活例子:
防抖:坐电梯,有人进电梯,就重新等 10 秒,没人进来了,电梯才关门。(连续触发,只在最后一次 执行)
节流:红绿灯,30 秒放行一次,不管多少车来,最多 30 秒过一次车。(连续触发,固定间隔执行)
防抖(debounce)
解决什么问题
事件频繁连续触发 ,但是我们不想每次触发都执行函数,只在触发停止之后,再执行一次。
不防抖的后果:疯狂重复执行函数,浪费性能,请求发一大堆。
应用场景
-
搜索框输入联想 :用户打字的时候,不要每敲一个字就发接口请求;等用户停止打字 300ms之后,再去请求搜索推荐。
-
窗口 resize(浏览器缩放窗口):拖动窗口大小,不要每时每刻执行,等拖动停下再执行布局计算。
-
表单输入实时校验
手写防抖(JS,用你习惯的箭头函数)
// 防抖函数 let debounce = (fn, delay) => { let timer = null; // 返回新函数 return (...args) => { // 只要再次触发,就清除上一次定时器 clearTimeout(timer); // 重新计时 timer = setTimeout(() => { fn(...args); }, delay); } } // 使用示例:搜索框 let searchInput = document.querySelector('#search'); // 包装搜索请求函数,延迟300ms执行 let searchFn = debounce( (val) => { console.log('发请求搜索:', val); }, 300); searchInput.addEventListener('input', (e)=>{ searchFn(e.target.value); })逻辑复盘:每次输入触发 input 事件 → 清除旧定时器,重新计时;停下不输入,定时器走完,才执行搜索。
节流(throttle)
解决什么问题
事件高频连续触发 ,限制函数在规定时间内最多只能跑 1 次。
哪怕疯狂触发事件,也不会无限执行,按固定频率执行。
应用场景
- 滚动监听 scroll:页面滚动,监听滚动位置、懒加载、回到顶部按钮显示,不能滚动每一像素都执行。比如每 200ms 执行一次。
- 鼠标移动 mousemove (鼠标拖拽、绘图)
- 按钮频繁点击(短时间多次点击,限制一段时间只能触发一次)
手写节流(时间戳版本,箭头函数)
let throttle = (fn, interval) => {
let lastTime = 0;
return (...args) => {
let now = Date.now();
if( now - lastTime >= interval ){
fn(...args);
lastTime = now;
}
}
}
// 使用示例:页面滚动
let scrollHandle = throttle(()=>{
console.log('监听滚动位置');
}, 200)
window.addEventListener('scroll', scrollHandle)
逻辑复盘:记录上次执行时间;当前时间减去上次时间大于间隔,才执行函数,并更新上次时间。