防抖、节流是什么?区别和应用场景?
防抖和节流都是用来控制函数执行频率的优化手段
防抖
shell
# 什么时候防抖?
连续触发只执行一次
# 使用场景?
搜索框输入、窗口尺寸调整、按钮重复提交
# 实现:基础防抖 + 立即执行状态的防抖函数
function debounce(func, delay, immediate = false) {
let timer = null;
return function(...args) {
const context = this;
if (immediate && !timer) {
func.apply(context, args);
}
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
if (!immediate) {
func.apply(context, args);
}
timer = null;
}, delay);
};
}节流
shell
# 什么时候节流?
连续触发按固定频率执行
# 使用场景?
滚动监听、拖拽位置更新、搜索联想
# 实现:基础节流 + 确保最后一次执行
function throttle(func, delay) {
let timer = null;
let previous = 0;
return function(...args) {
const context = this;
const now = Date.now();
const remaining = delay - (now - previous);
// 超过时间间隔或时间调整(剩余时间小于0)
if (remaining <= 0 || remaining > delay) {
if (timer) {
clearTimeout(timer);
timer = null;
}
previous = now;
func.apply(context, args);
} else if (!timer) {
timer = setTimeout(() => {
previous = Date.now();
timer = null;
func.apply(context, args);
}, remaining);
}
};
}附:基础防抖、定时器与时间戳节流
防抖和节流常用来收敛短时间内反复触发的事件(如滚动、输入),减少实际执行次数,从而提高性能
提示
防抖:短时间内连续触发只是执行一次
节流:每隔一段固定时间执行一次
实现防抖
指定时间内触发重新计时,指定时间外触发执行回调
- 定义防抖函数把目标方法作为参数传入
- 函数闭包保留状态:函数内部返回函数,在闭包函数外部保留定时器初始状态
- 设置定时器
- 定时时间内如果定时器存在则清理定时器重新开始计时,过了定时器时间则执行目标方法
js
// 使用防抖函数
const el = document.getElementById("debounce");
el.addEventListener(
"click",
debounce(function () {
console.log(" hello world ");
}, 1000)
);
// 通过 setTimeout 实现
function debounce(fn, delay) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
};
}实现节流
指定时间内若已触发过则按间隔执行,常用定时器或时间戳两种思路。
- 方案一:定时器实现
- 定义节流函数把目标方法作为参数传入
- 函数闭包保留状态:函数内部返回函数,在闭包函数外部保留定时状态
- 设置定时器
- 定时时间内如果定时器存在什么也不做(if 分支),过了定时器时间则执行目标方法并清理定时器
js
// 通过 setTimeout 实现
function throttled2(fn, delay = 500) {
let timer = null;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
};
}- 方案二:时间戳实现
- 定义节流函数把目标方法作为参数传入
- 函数闭包保留状态:函数内部返回函数,在闭包函数外部记录上次执行时间
- 根据时间差决定是否执行目标方法和更新时间
ts
// 通过时间戳实现
function throttled1(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();
}
};
}防抖和节流的使用场景
防抖的使用场景?
- 输入框实时搜索
- 表单验证
- 按钮
节流的使用场景?
- 滚动事件监听
- 搜索框联想
