防抖节流函数是什么
防抖函数(debounce):n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
节流函数(throttle):n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
为什么要防抖节流函数
本质上是优化高频率执行代码的一种手段,对浪费资源的事件采取限制调用次数的限制
常见应用场景
防抖在连续的事件,只需触发一次回调的场景有:
- 搜索框搜索输入。只需用户最后一次输入完,再发送请求
- 手机号、邮箱验证输入检测
- 窗口大小
resize
。只需窗口调整完成后,计算窗口大小。防止重复渲染。
节流在间隔一段时间执行一次回调的场景有:
- 滚动加载,加载更多或滚到底部监听
- 搜索框,搜索联想功能
代码实现
防抖
function debounce(func, wait) {
let timeout;
return function () {
let context = this; // 保存this指向
let args = arguments; // 拿到event对象
clearTimeout(timeout);
timeout = setTimeout(function () {
func.apply(context, args);
}, wait);
};
}
防抖如果需要立即执行,可加入第三个参数用于判断,实现如下:
function debounce(func, wait, immediate) {
let timeout;
return function () {
let context = this;
let args = arguments;
if (timeout) clearTimeout(timeout); // timeout 不为null
if (immediate) {
let callNow = !timeout; // 第一次会立即执行,以后只有事件执行后才会再次触发
timeout = setTimeout(function () {
timeout = null;
}, wait);
if (callNow) {
func.apply(context, args);
}
} else {
timeout = setTimeout(function () {
func.apply(context, args);
}, wait);
}
};
}
节流
利用定时器实现节流函数:
function throttled(fn, delay = 500) {
let timer = null;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
};
}
利用时间戳实现节流函数,时间会立即执行,停止触发后没办法再次执行:
function throttled(fn, delay = 500) {
let oldTime = Date.now();
return function (...args) {
let newTime = Date.now();
if (newTime - oldTime >= delay) {
fn.apply(null, args);
oldTime = Date.now();
}
};
}
将时间戳写法的特性与定时器写法的特性相结合,更精确:
function throttled(fn, delay) {
let timer = null;
let startTime = Date.now();
return function () {
let curTime = Date.now(); // 当前时间
let remaining = delay - (curTime - startTime); // 从上一次到现在,还剩下多少多余时间
let context = this;
let args = arguments;
clearTimeout(timer);
if (remaining <= 0) {
fn.apply(context, args);
startTime = Date.now();
} else {
timer = setTimeout(fn, remaining);
}
};
}
总结
相同点
- 都可以通过使用
setTimeout
实现 - 目的都是,降低回调执行频率。节省计算资源
不同点
函数防抖 | 函数节流 |
---|---|
在一段连续操作结束后,处理回调,利用 clearTimeout 和 setTimeout 实现 | 在一段连续操作中,每一段时间只执行一次,频率较高的事件中使用来提高性能 |
希望一定时间连续触发的事件只在最后执行一次 | 希望一定时间连续触发的事件一段时间内只执行一次 |