文章中英模式
布鲁斯前端JS面试题目 - 实现防抖函数处理输入事件
学习如何实现防抖函数来优化表单输入、搜索建议和按钮点击等事件,提升用户体验与前端效能。
文章中英模式
懒得看文章?那就来看视频吧
什么是防抖 (Debounce)?
防抖是一种前端优化技术,用于控制函数触发的频率,尤其适用于处理用户快速连续操作,如:输入框打字、窗口调整大小、滚动事件等。
核心原理:延迟执行函数,若指定时间内触发多次,则以最后一次操作为准。
防抖应用场景
- 1. 搜索框输入建议(等用户停止输入后才发送请求)
- 2. 表单验证(用户输入完毕后再验证)
- 3. 窗口调整大小时的重新计算
- 4. 避免按钮重复点击提交
- 5. 即时保存文章草稿
基本实现:防抖函数 (Debounce)
下面是一个简单的防抖函数实现,接收一个函数和延迟时间作为参数:
function debounce(func, delay = 300) {
let timer = null;
return function(...args) {
// 保存 this 上下文
const context = this;
// 清除之前的计时器
clearTimeout(timer);
// 设置新的计时器
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
};
}
使用示例:搜索输入框
// 定义一个搜索函数
function search(query) {
console.log("搜索:", query);
// 通常这里会有 API 请求
}
// 创建防抖版本的搜索函数 (500ms延迟)
const debouncedSearch = debounce(search, 500);
// 绑定到输入事件
document.querySelector('#search-input').addEventListener('input', function(e) {
debouncedSearch(e.target.value);
});
进阶实现:带立即执行选项的防抖
有时我们需要首次触发立即执行,之后再进行防抖,例如:表单验证时希望立即反馈首次输入。
function advancedDebounce(func, delay = 300, immediate = false) {
let timer = null;
return function(...args) {
const context = this;
const callNow = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
if (!immediate) {
func.apply(context, args);
}
}, delay);
// 如果是立即执行模式且首次触发,立即调用函数
if (callNow) {
func.apply(context, args);
}
};
}
使用范例:表单验证
// 验证电子邮件格式
function validateEmail(email) {
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+.[a-zA-Z]{2,6}$/;
const isValid = emailRegex.test(email);
if (!isValid) {
document.querySelector('#email-error').textContent = '请输入有效的电子邮件';
} else {
document.querySelector('#email-error').textContent = '';
}
}
// 立即验证首次输入,之后等用户输入完毕再验证
const debouncedValidate = advancedDebounce(validateEmail, 500, true);
document.querySelector('#email-input').addEventListener('input', function(e) {
debouncedValidate(e.target.value);
});
防抖函数处理常见问题
1. 如何处理 this 绑定问题
在类组件中使用防抖时,需要正确处理 this
的绑定,可以使用箭头函数或在构造函数中绑定。
class SearchComponent extends React.Component {
constructor(props) {
super(props);
this.state = { query: '' };
// 绑定 this 到防抖后的方法
this.debouncedSearch = debounce(this.search.bind(this), 500);
// 或直接使用箭头函数
// this.search = () => { /* ... */ };
// this.debouncedSearch = debounce(this.search, 500);
}
search() {
// 这里可以安全地使用 this
console.log('搜索:', this.state.query);
}
handleChange = (e) => {
this.setState({ query: e.target.value });
this.debouncedSearch();
}
render() {
return (
<input
type="text"
value={this.state.query}
onChange={this.handleChange}
/>
);
}
}
2. 取消防抖执行
有时我们需要取消延迟执行,例如组件卸载时取消尚未执行的调用:
function debounceWithCancel(func, delay = 300) {
let timer = null;
function debounced(...args) {
const context = this;
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(context, args);
}, delay);
}
// 添加取消方法
debounced.cancel = function() {
clearTimeout(timer);
timer = null;
};
return debounced;
}
// 在 React 组件中使用
useEffect(() => {
const debouncedFunc = debounceWithCancel(myFunction, 500);
// 注册事件监听
element.addEventListener('input', debouncedFunc);
// 清理
return () => {
element.removeEventListener('input', debouncedFunc);
debouncedFunc.cancel(); // 取消尚未执行的调用
};
}, []);