前言
前端的交互中,有些操作需要持续触发,而且频率非常高。比如:resize, scroll, mousemove, input 等事件。而为了性能和效率,我们不需要让事件触发太多次。这就诞生了函数的防抖和节流。
防抖(debounce)
防抖简单说就是在设定的时间内,虽然操作上持续触发,通过定时器约束,我们也只执行函数触发的最后一次。
防抖函数可以分为延迟执行版和立即执行版
延迟执行版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| /* fn: 需要防抖的函数 wait: 延迟毫秒数 return: 函数 */ // 延迟执行 function debounce(fn, wait) { var timer; // 全局的定时器 id return function () { var that = this; // 将函数被调用时的 this 保存 var args = arguments; // 保存函数的参数 if (timer) { clearTimeout(timer); // 清除 wait 时间内频繁调用函数产生的定时器 } timer = setTimeout(() => { fn.apply(that, args); // 将传递进来的 fn 使用 apply 调用,将 this 指向改为保存的 that,同时进行传参 }, wait); }; }
|
立即执行版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| // 立即执行 function debounce(fn, wait) { var timer; return function () { var that = this; var args = arguments; if (timer) { clearTimeout(timer); } if (!timer) fn.apply(that, args); // 首次进入, timer 为空,执行 fn 函数 timer = setTimeout(() => { timer = null; // wait 毫秒后设置 timer 为空 }, wait); }; }
|
防抖应用场景
节流(throttle)
节流就是按照给定的时间有规律的执行函数,可以通过时间戳和定时器实现。
节流函数可以分为定时器版和时间戳版
定时器版
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| // 定时器版 function throttle(fn, wait) { let timer; return function () { const that = this; const args = arguments; if (!timer) { timer = setTimeout(() => { fn.apply(that, args); timer = null; }, wait); } }; }
|
时间戳版
1 2 3 4 5 6 7 8 9 10 11 12 13
| // 时间戳版 function throttle(fn, wait) { let previous = 0; return function () { const that = this; const args = arguments; let now = Date.now(); if (now - previous > wait) { fn.apply(that, args); previous = now; } }; }
|
节流应用场景
- 元素拖动
- 搜索联想
- 移动端上滑加载时判断距离底部的位置