防抖(Debounce)和节流(Throttle)是两种常用的优化高频率执行代码的技术。它们主要用于限制函数执行的频率,以避免在短时间内触发大量函数调用导致性能问题。
简单来说,防抖和节流都是用来控制函数执行频率的技术
它们本身不属于任何官方标准或规范,而是一种基于JavaScript(或其它编程语言)实现的"编程技巧"或"设计模式"。 两者核心区别在于 触发频率 和 执行时机
1、防抖
生动比喻: 电梯门 电梯门不会在每个人进来时立刻关闭,而是会等待一段时间(比如5秒)。如果在这5秒内又有人进来,计时器会重置,再等5秒。直到连续5秒内都没有新的人进来,电梯门才会真正关闭并开始运行。 工作原理:
-
设置一个定时器。
-
每次触发事件时,都取消之前的定时器,并设置一个新的定时器。
-
如果在规定的时间间隔内没有再次触发事件,那么定时器中的函数才会被执行。
防抖函数示例
javascript
function debounce(func, wait) {
// 确保只执行一次,通常是最后一次
// **输入框连续输入,只有在输入完成后才执行搜索**
let timeoutId;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeoutId = setTimeout(function() {
func.apply(context, args);
}, wait);
};
}
搜索框防抖
ini
const searchInput = document.getElementById('search');
const suggestions = document.getElementById('suggestions');
const fetchSuggestions = debounce(async (query) => {
if (!query.trim()) {
suggestions.innerHTML = '';
return;
}
try {
const response = await fetch(`/api/suggestions?q=${encodeURIComponent(query)}`);
const data = await response.json();
displaySuggestions(data);
} catch (error) {
console.error('搜索建议获取失败:', error);
}
}, 300);
searchInput.addEventListener('input', (e) => {
fetchSuggestions(e.target.value);
});
function displaySuggestions(items) {
suggestions.innerHTML = items.map(item =>
`<div class="suggestion">${item}</div>`
).join('');
}
响应式布局调整,窗口调整防抖
scss
const handleResize = debounce(() => {
const width = window.innerWidth;
if (width < 768) {
// 移动端布局
adjustMobileLayout();
} else if (width < 1024) {
// 平板布局
adjustTabletLayout();
} else {
// 桌面端布局
adjustDesktopLayout();
}
}, 250);
window.addEventListener('resize', handleResize);
2、节流
生动比喻: 王者荣耀或者英雄联盟中的技能冷却 一个技能释放后,会进入冷却时间(比如12秒)。在这3秒内,无论你如何疯狂地按技能键,这个技能都不会再次被释放。直到12秒冷却结束,你按下按键,技能才会再次释放并进入下一个冷却周期。 工作原理:
-
设置一个标志位或记录上一次执行的时间戳。
-
当事件触发时,检查是否已经过了规定的冷却时间。
-
如果过了,就执行函数并更新标志位/时间戳;如果没到,就忽略这次触发。
节流函数
ini
function throttle(func, wait) {
// **函数在规定时间内只执行一次,并且每隔规定时间结束后才会执行下一次,不会在规定时间内重复触发**
// **按钮点击事件,防止重复点击,多次执行**
let previous = 0;
return function() {
const now = Date.now();
const context = this;
const args = arguments;
if (now - previous > wait) {
func.apply(context, args);
previous = now;
}
};
}
无限滚动加载节流
ini
const container = document.getElementById('scroll-container');
let loading = false;
const checkScroll = throttle(() => {
const { scrollTop, scrollHeight, clientHeight } = container;
// 距离底部100px时加载更多
if (scrollHeight - scrollTop - clientHeight < 100 && !loading) {
loading = true;
loadMoreContent();
}
}, 200);
container.addEventListener('scroll', checkScroll);
async function loadMoreContent() {
try {
const response = await fetch('/api/more-content');
const data = await response.json();
appendContent(data);
} catch (error) {
console.error('加载失败:', error);
} finally {
loading = false;
}
}
按钮点击节流
ini
// 防止重复提交
const submitButton = document.getElementById('submit');
let submitting = false;
const handleSubmit = throttle(async (e) => {
e.preventDefault();
if (submitting) return;
submitting = true;
submitButton.disabled = true;
submitButton.textContent = '提交中...';
try {
const formData = new FormData(document.getElementById('form'));
await fetch('/api/submit', {
method: 'POST',
body: formData
});
alert('提交成功!');
} catch (error) {
console.error('提交失败:', error);
alert('提交失败,请重试');
} finally {
submitting = false;
submitButton.disabled = false;
submitButton.textContent = '提交';
}
}, 1000);
submitButton.addEventListener('click', handleSubmit);
最后,前端防抖或者节流本质都是JavaScript的编程技巧,属于JS中的上层武学,掌握它对于编写高质量、高性能的web应用有着重要的作用!!!