概念:防抖是一种确保在一段时间内,函数只执行一次的技术。具体来说,当事件被触发时,会延迟执行函数。如果在延迟时间内再次触发事件,则重新开始计时。只有在延迟时间结束后没有再次触发事件,函数才会执行。
应用场景:
实现防抖:
function debounce(fn, delay) {
let timeoutId; // 用于存储定时器的ID
return function(...args) {
clearTimeout(timeoutId); // 清除前一个定时器
timeoutId = setTimeout(() => {
fn.apply(this, args); // 定时器到期后执行函数
}, delay);
};
}
// 示例:防抖搜索框
const searchInput = document.getElementById('search');
const handleSearch = debounce((event) => {
console.log('Searching:', event.target.value);
}, 300); // 延迟300毫秒
searchInput.addEventListener('input', handleSearch);
概念:节流是一种确保在一定时间内,函数最多执行一次的技术。具体来说,当事件被频繁触发时,在每个固定的时间段内,只允许函数执行一次。
应用场景:
实现节流:
function throttle(fn, limit) {
let lastCall = 0; // 记录上次函数执行的时间
return function(...args) {
const now = Date.now(); // 当前时间
if (now - lastCall >= limit) { // 如果距离上次执行时间超过了限制时间
lastCall = now; // 更新上次执行时间
fn.apply(this, args); // 执行函数
}
};
}
// 示例:节流滚动事件
const handleScroll = throttle(() => {
console.log('Scrolling');
}, 200); // 每200毫秒最多执行一次
window.addEventListener('scroll', handleScroll);
防抖:
节流:
以下是更详细的防抖和节流实现,包括立即执行和取消功能:
function debounce(fn, delay, immediate) {
let timeoutId; // 用于存储定时器的ID
function debounced(...args) {
const callNow = immediate && !timeoutId; // 是否立即执行
clearTimeout(timeoutId); // 清除前一个定时器
timeoutId = setTimeout(() => {
timeoutId = null; // 定时器到期后清空timeoutId
if (!immediate) fn.apply(this, args); // 如果不是立即执行,延迟时间到期后执行函数
}, delay);
if (callNow) fn.apply(this, args); // 立即执行函数
}
debounced.cancel = () => {
clearTimeout(timeoutId); // 取消防抖
timeoutId = null;
};
return debounced;
}
// 示例:立即执行防抖
const log = debounce(() => console.log('Hello'), 1000, true);
window.addEventListener('resize', log);
function throttle(fn, limit, immediate) {
let lastCall = 0; // 记录上次函数执行的时间
let timeoutId; // 用于存储定时器的ID
function throttled(...args) {
const now = Date.now(); // 当前时间
if (immediate && !lastCall) { // 是否立即执行
lastCall = now;
fn.apply(this, args); // 立即执行函数
}
if (now - lastCall >= limit) { // 如果距离上次执行时间超过了限制时间
clearTimeout(timeoutId); // 清除前一个定时器
lastCall = now; // 更新上次执行时间
fn.apply(this, args); // 执行函数
} else if (!timeoutId) { // 如果没有定时器,则设置一个定时器
timeoutId = setTimeout(() => {
lastCall = immediate ? Date.now() : 0;
timeoutId = null; // 定时器到期后清空timeoutId
fn.apply(this, args); // 延迟时间到期后执行函数
}, limit - (now - lastCall));
}
}
throttled.cancel = () => {
clearTimeout(timeoutId); // 取消节流
lastCall = 0;
timeoutId = null;
};
return throttled;
}
// 示例:立即执行节流
const log = throttle(() => console.log('Hello'), 1000, true);
window.addEventListener('scroll', log);