JavaScript - 防抖和节流

#防抖 (Debounce)

防抖函数 是一种优化高频率触发事件处理的技术。依据MDN文档,某些事件(如滚动、调整窗口大小、键盘输入)可能会在短时间内多次触发,这可能导致性能问题。

防抖原理:在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则 重新计时 。这确保函数只在用户停止操作一段时间后才执行。

常见应用场景

  • 搜索框输入查询(输入完成后才发送请求)
  • 窗口调整后重新布局
  • 按钮提交事件处理
  • 输入验证

#基本实现

防抖基本实现
JavaScript
function debounce(fn, wait) {
let timer = null
return function () {
const context = this
const args = arguments
// 如果此时存在定时器,则取消之前的定时器重新记时
if (timer) {
clearTimeout(timer)
timer = null
}
// 设置定时器,使事件间隔指定时间后执行
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}

#实际应用示例

搜索框防抖示例
JavaScript
// HTML: <input id="search-input" type="text" placeholder="输入关键词搜索..." />
const searchInput = document.getElementById('search-input')
// 未优化的搜索函数
function search(query) {
console.log(`正在搜索: ${query}`)
// 实际中这里会发起API请求
}
// 使用防抖优化后的搜索函数
const debouncedSearch = debounce(search, 500)
// 添加事件监听
searchInput.addEventListener('input', function(e) {
debouncedSearch(e.target.value)
})

#带立即执行选项的增强版防抖

有时我们需要函数在事件触发时 立即执行 一次,然后等待一段时间后才能再次执行:

立即执行的防抖函数
JavaScript
function debounce(fn, wait, immediate = false) {
let timer = null
return function() {
const context = this
const args = arguments
// 如果需要立即执行
const callNow = immediate && !timer
// 清除现有定时器
if (timer) {
clearTimeout(timer)
}
// 设置新定时器
timer = setTimeout(() => {
timer = null
if (!immediate) {
fn.apply(context, args)
}
}, wait)
// 如果是立即执行,调用函数
if (callNow) {
fn.apply(context, args)
}
}
}

#节流 (Throttle)

节流函数 限制一个函数在一定时间内只执行一次。与防抖不同,节流确保函数以 固定的速率 执行,而不是等待一段静默时间后才执行。

节流原理:规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行。如果在同一个单位时间内某事件被触发多次,只有一次能生效。

常见应用场景

  • 滚动事件处理(如 懒加载无限滚动
  • 鼠标移动事件(如拖拽)
  • 窗口调整大小
  • 游戏中的按键控制

#基本实现

节流基本实现
JavaScript
function throttle(fn, delay) {
let lastTime = 0
return function () {
const context = this
const args = arguments
const nowTime = Date.now()
// 如果两次时间间隔超过了指定时间,则执行函数
if (nowTime - lastTime >= delay) {
lastTime = nowTime
fn.apply(context, args)
}
}
}

#使用定时器实现节流

除了使用 时间戳 ,还可以使用 定时器 实现节流:

定时器实现节流
JavaScript
function throttle(fn, delay) {
let timer = null
return function() {
const context = this
const args = arguments
if (!timer) {
timer = setTimeout(() => {
fn.apply(context, args)
timer = null
}, delay)
}
}
}

#实际应用示例

滚动事件节流
JavaScript
// 未优化的滚动处理函数
function handleScroll() {
console.log('滚动位置:', window.scrollY)
// 处理滚动逻辑,如检查元素是否进入视口等
}
// 使用节流优化后的滚动处理函数
const throttledScroll = throttle(handleScroll, 200)
// 添加事件监听
window.addEventListener('scroll', throttledScroll)

#防抖与节流的区别

两者都是控制函数执行频率的技术,但适用场景和行为模式不同:

特性防抖(Debounce)节流(Throttle)
执行时机等待期结束后 执行固定频率 执行
适用场景输入框搜索、表单提交滚动处理、拖拽
行为特点多次触发只执行 最后一次保证按 时间间隔 执行
性能影响减少函数执行次数均匀分散函数执行

#总结

防抖节流 都是优化性能的重要技术,尤其在处理高频率触发的事件时。通过理解它们的工作原理和适用场景,可以显著提高Web应用的响应性和用户体验。选择哪种技术取决于具体的用例和期望的用户体验。