在日常开发中,我们会经常遇到搜索查询,用户在输入过程中会触发 input 值的改变而持续触发函数调用。或者在用户在商品搜索页滑动浏览商品时,如果我们监听了窗口滚动来发送埋点请求的话,就会频繁触发接口调用。
但有时候我们并不希望用户的持续操作过程中,会频繁触发接口的调用。而为了限制这种短时间内高频触发函数调用情况发生,我们可以借助防抖和节流。
函数防抖和节流,都是通过控制事件触发频率达到优化函数执行效率的效果。
一、防抖
防抖,顾名思义,防止抖动。用于将用户的操作行为触发转换为程序行为触发,防止用户操作的结果抖动。一段时间内,事件在我们规定的间隔 n 秒内多次执行,回调只会执行一次。
特点:等待某种操作停止后,加以间隔进行操作。
(1) 持续触发不执行;
(2) 不触发的一段时间之后再执行。
const debounce = function(callback, delay) {
let timer = null;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(callback.bind(this,...args), delay);
}
}
闭包:表现为函数 return 函数,会造成内存的泄漏。
应用场景:
(1) mousemove 鼠标滑动事件;
(2) 输入框搜索事件等。
案例:为文本框添加防抖动作
<input type="text" id="input" />
function fn(value) {
console.log(value);
}
var input = document.getElementById('input');
var debounceFun = debounce(fn, 1000); // 很关键的一步,debounceFun = return function(value)
input.addEventListener('keyup', function(e) {
debounceFun(e.target.value);
});
二、节流
节流,顾名思义,控制流量。用于用户在与页面交互时控制事件发生的频率,一般场景是单位的时间或其它间隔内定时执行操作。一段时间内,事件在每次到达我们规定的间隔 n 秒时触发一次。
特点:每等待某种间隔后,进行操作:
(1) 持续触发并不会执行多次;
(2) 到一定时间 / 其它间隔(如滑动的高度)再去执行。
const throttle = function(callback, delay) {
let enable = true;
return function(...args) {
if (enable) {
enable = false;
callback.apply(this, args);
setTimeout(() => {
enable = true;
}, delay);
}
};
};
应用场景:
(1) 埋点场景。商品搜索列表、商品橱窗等,用户滑动时 定时 / 定滑动的高度 发送埋点请求;
(2) 运维系统查看应用运行日志时,每 n 秒刷新一次。
案例:为按钮添加节流动作
<button id="button">点击</button>
function handle() {
console.log(Math.random());
}
var button = document.getElementById('button');
button.onclick = throttle(handle, 2000);
三、防抖和节流的区别
防抖可能用于无法预知的用户主动行为,如用户输入内容去服务端动态搜索结果。用户打字的速度等是无法预知的,具有非规律性。
节流可能用于一些非用户主动行为或者可预知的用户主动行为,如用户滑动商品橱窗时发送埋点请求、滑动固定的高度是已知的逻辑,具有规律性。
借用防抖和节流的思想,来控制函数执行的时机,可以节约性能,避免页面卡顿等带来不好的用户体验。