js防抖和节流实现
防抖(Debounce)的实现
防抖的核心思想是在事件触发后等待一段时间再执行回调,若在等待期间再次触发事件,则重新计时。适用于输入框搜索联想、窗口大小调整等场景。
基础实现:
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
立即执行版本:
function debounce(func, delay, immediate) {
let timeoutId;
return function(...args) {
const context = this;
const later = () => {
timeoutId = null;
if (!immediate) func.apply(context, args);
};
const callNow = immediate && !timeoutId;
clearTimeout(timeoutId);
timeoutId = setTimeout(later, delay);
if (callNow) func.apply(context, args);
};
}
节流(Throttle)的实现
节流的核心思想是在固定时间间隔内只执行一次回调。适用于滚动事件、高频点击等场景。
时间戳版本:
function throttle(func, limit) {
let lastTime;
return function(...args) {
const now = Date.now();
if (!lastTime || now - lastTime >= limit) {
func.apply(this, args);
lastTime = now;
}
};
}
定时器版本:
function throttle(func, limit) {
let timeoutId;
return function(...args) {
if (!timeoutId) {
timeoutId = setTimeout(() => {
func.apply(this, args);
timeoutId = null;
}, limit);
}
};
}
结合版本(更精确控制):
function throttle(func, limit) {
let lastTime = 0;
let timeoutId;
return function(...args) {
const now = Date.now();
const remaining = limit - (now - lastTime);
if (remaining <= 0) {
if (timeoutId) {
clearTimeout(timeoutId);
timeoutId = null;
}
func.apply(this, args);
lastTime = now;
} else if (!timeoutId) {
timeoutId = setTimeout(() => {
func.apply(this, args);
timeoutId = null;
lastTime = Date.now();
}, remaining);
}
};
}
使用示例
防抖示例:
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(function() {
console.log('Searching:', this.value);
}, 500);
searchInput.addEventListener('input', debouncedSearch);
节流示例:
window.addEventListener('scroll', throttle(function() {
console.log('Scrolling:', window.scrollY);
}, 200));
关键区别
防抖在连续触发时只执行最后一次,节流在固定时间间隔内必定执行一次。根据实际场景需求选择合适的方法。高频事件中需要即时反馈用节流,只需最终结果用防抖。







