深入理解与实现 JavaScript 防抖函数
什么是防抖(Debounce)
防抖是一种常用的前端性能优化技术,主要用于控制函数执行的频率。当一个事件被频繁触发时,防抖可以确保只有在事件停止触发一段时间后,才会真正执行处理函数。
典型应用场景
- 搜索框输入联想
- 窗口大小调整事件
- 表单提交按钮的多次点击
- 滚动事件处理
防抖函数实现解析
// 定义防抖函数
function debounce(func: Function, wait: number) {
let timeout: ReturnType<typeof setTimeout> | null = null
return function(this: any, ...args: any[]) {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
func.apply(this, args)
}, wait)
}
}
代码分解
-
函数参数:
func
: 需要被防抖处理的原始函数wait
: 等待时间(毫秒),在这段时间内如果再次触发则重新计时
-
闭包变量:
timeout
: 存储定时器ID,利用闭包特性保持状态
-
返回函数:
- 每次调用都会清除之前的定时器
- 设置新的定时器,在等待时间结束后执行原始函数
- 使用
apply
确保正确的this
上下文和参数传递
实际应用示例
// 原始提交函数
function returnsWorkOrderconfirmsubmit(data: any) {
console.log('提交数据:', data)
// 实际的提交逻辑...
}
// 创建防抖后的提交函数
const debouncedSubmit = debounce(returnsWorkOrderconfirmsubmit, 300)
// 模拟快速连续调用
debouncedSubmit({id: 1}) // 不会立即执行
debouncedSubmit({id: 2}) // 取消前一个,重新计时
debouncedSubmit({id: 3}) // 取消前一个,重新计时
// 300ms后只会执行最后一次调用,输出: 提交数据: {id: 3}
防抖与节流(Throttle)的区别
特性 | 防抖(Debounce) | 节流(Throttle) |
---|---|---|
执行时机 | 事件停止触发后一段时间执行 | 固定时间间隔执行 |
重置机制 | 每次新触发都会重置计时器 | 不会重置,按固定频率执行 |
适用场景 | 输入联想、提交按钮防重复点击 | 滚动事件、鼠标移动事件 |
TypeScript 增强实现
上述实现已经使用了TypeScript,其中几个关键点:
ReturnType<typeof setTimeout>
: 获取setTimeout的返回类型this: any
: 指定函数内部的this类型...args: any[]
: 剩余参数类型定义
进阶优化
可以扩展基础防抖函数,添加更多功能:
interface DebounceOptions {
leading?: boolean // 是否在开始时立即执行
maxWait?: number // 最大等待时间
}
function advancedDebounce(func: Function, wait: number, options: DebounceOptions = {}) {
let timeout: ReturnType<typeof setTimeout> | null = null
let lastCallTime: number = 0
return function(this: any, ...args: any[]) {
const now = Date.now()
if (options.leading && !timeout) {
func.apply(this, args)
}
if (timeout) {
clearTimeout(timeout)
}
// 检查是否达到最大等待时间
if (options.maxWait && (now - lastCallTime) >= options.maxWait) {
func.apply(this, args)
lastCallTime = now
} else {
timeout = setTimeout(() => {
func.apply(this, args)
timeout = null
}, wait)
}
lastCallTime = now
}
}
总结
防抖是前端开发中非常重要的性能优化技术,合理使用可以显著提升应用性能。理解其实现原理有助于我们在不同场景下灵活应用,同时也能更好地理解函数式编程和闭包的概念。