防抖(Debounce)与节流(Throttle)
防抖(Debounce)
防抖函数指的是触发事件后,在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
实现原理
function debounce(fn, delay) {
let timer = null;
return function (...args) {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
};
}
使用示例
// 防抖应用场景:搜索框输入,窗口大小调整
const debouncedSearch = debounce(function (keyword) {
console.log("搜索关键词:", keyword);
}, 300);
// 用户输入时调用
document.querySelector("#search").addEventListener("input", function (e) {
debouncedSearch(e.target.value);
});
节流(Throttle)
节流函数指的是在一段时间内,函数只能执行一次,也就是说在规定的时间内,函数只能执行一次。
实现原理
function throttle(fn, interval) {
let lastTime = 0;
return function (...args) {
const now = Date.now();
if (now - lastTime >= interval) {
fn.apply(this, args);
lastTime = now;
}
};
}
使用示例
// 节流应用场景:滚动事件,鼠标移动,DOM元素拖拽
const throttledScroll = throttle(function () {
console.log("页面滚动了");
}, 500);
// 滚动时调用
window.addEventListener("scroll", throttledScroll);
防抖与节流的区别
特性 | 防抖(Debounce) | 节流(Throttle) |
---|---|---|
目的 | 将多次执行变为最后一次执行 | 将多次执行变成每隔一段时间执行一次 |
场景 | 搜索框输入、窗口大小调整 | 滚动事件、鼠标移动、DOM 元素拖拽 |
原理 | 清除之前的定时器,重新设置新的定时器 | 判断当前时间与上次执行的时间差 |
进阶版本实现
立即执行版本的防抖
function debounceImmediate(fn, delay, immediate = false) {
let timer = null;
return function (...args) {
if (timer) clearTimeout(timer);
// 立即执行版本
if (immediate && !timer) {
fn.apply(this, args);
}
timer = setTimeout(() => {
if (!immediate) fn.apply(this, args);
timer = null;
}, delay);
};
}
可取消的节流
function throttleWithCancel(fn, interval) {
let lastTime = 0;
let timer = null;
const throttled = function (...args) {
const now = Date.now();
const remaining = interval - (now - lastTime);
if (remaining <= 0) {
if (timer) {
clearTimeout(timer);
timer = null;
}
fn.apply(this, args);
lastTime = now;
} else if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
lastTime = Date.now();
timer = null;
}, remaining);
}
};
throttled.cancel = function () {
if (timer) {
clearTimeout(timer);
timer = null;
}
};
return throttled;
}