JavaScript - 防抖和节流
April 12, 2025
6 min read
#防抖 (Debounce)
防抖函数
是一种优化高频率触发事件处理的技术。依据MDN文档,某些事件(如滚动、调整窗口大小、键盘输入)可能会在短时间内多次触发,这可能导致性能问题。
防抖原理:在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则 重新计时
。这确保函数只在用户停止操作一段时间后才执行。
常见应用场景:
- 搜索框输入查询(输入完成后才发送请求)
- 窗口调整后重新布局
- 按钮提交事件处理
- 输入验证
#基本实现
防抖基本实现JavaScript
function debounce(fn, wait) {let timer = nullreturn function () {const context = thisconst 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 = nullreturn function() {const context = thisconst args = arguments// 如果需要立即执行const callNow = immediate && !timer// 清除现有定时器if (timer) {clearTimeout(timer)}// 设置新定时器timer = setTimeout(() => {timer = nullif (!immediate) {fn.apply(context, args)}}, wait)// 如果是立即执行,调用函数if (callNow) {fn.apply(context, args)}}}
#节流 (Throttle)
节流函数
限制一个函数在一定时间内只执行一次。与防抖不同,节流确保函数以 固定的速率
执行,而不是等待一段静默时间后才执行。
节流原理:规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行。如果在同一个单位时间内某事件被触发多次,只有一次能生效。
常见应用场景:
- 滚动事件处理(如
懒加载
、无限滚动
) - 鼠标移动事件(如拖拽)
- 窗口调整大小
- 游戏中的按键控制
#基本实现
节流基本实现JavaScript
function throttle(fn, delay) {let lastTime = 0return function () {const context = thisconst args = argumentsconst nowTime = Date.now()// 如果两次时间间隔超过了指定时间,则执行函数if (nowTime - lastTime >= delay) {lastTime = nowTimefn.apply(context, args)}}}
#使用定时器实现节流
除了使用 时间戳
,还可以使用 定时器
实现节流:
定时器实现节流JavaScript
function throttle(fn, delay) {let timer = nullreturn function() {const context = thisconst args = argumentsif (!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应用的响应性和用户体验。选择哪种技术取决于具体的用例和期望的用户体验。