框架
版本
Debouncer API 参考
Throttler API 参考
速率限制器 API 参考
队列 API 参考
批处理器 API 参考
批处理器示例

防抖指南

速率限制、节流和防抖是控制函数执行频率的三种不同方法。每种技术以不同的方式阻止执行,使其具有“有损性”——这意味着当函数调用过于频繁时,某些函数调用将不会执行。了解何时使用每种方法对于构建高性能和可靠的应用程序至关重要。本指南将介绍 TanStack Pacer 的防抖概念。

防抖概念

防抖是一种延迟函数执行的技术,直到发生指定的非活动期为止。与允许突发执行达到限制的速率限制或确保均匀间隔执行的节流不同,防抖将多个快速函数调用合并为单个执行,该执行仅在调用停止后发生。这使得防抖非常适合处理突发事件,在这些事件中,你只关心活动稳定后的最终状态。

防抖可视化

text
防抖 (等待: 3 个滴答)
时间轴: [每个滴答 1 秒]
调用:        ⬇️  ⬇️  ⬇️  ⬇️  ⬇️     ⬇️  ⬇️  ⬇️  ⬇️               ⬇️  ⬇️
已执行:     ❌  ❌  ❌  ❌  ❌     ❌  ❌  ❌  ⏳   ->   ✅     ❌  ⏳   ->    ✅
             [=================================================================]
                                                        ^ 在没有调用 3 个滴答后在此处执行

             [突发调用]     [更多调用]   [等待]      [新的突发]
             未执行         重置计时器    [延迟执行]  [等待] [延迟执行]
防抖 (等待: 3 个滴答)
时间轴: [每个滴答 1 秒]
调用:        ⬇️  ⬇️  ⬇️  ⬇️  ⬇️     ⬇️  ⬇️  ⬇️  ⬇️               ⬇️  ⬇️
已执行:     ❌  ❌  ❌  ❌  ❌     ❌  ❌  ❌  ⏳   ->   ✅     ❌  ⏳   ->    ✅
             [=================================================================]
                                                        ^ 在没有调用 3 个滴答后在此处执行

             [突发调用]     [更多调用]   [等待]      [新的突发]
             未执行         重置计时器    [延迟执行]  [等待] [延迟执行]

何时使用防抖

当你希望在采取行动之前等待活动的“暂停”时,防抖特别有效。这使其非常适合处理用户输入或其他快速触发的事件,在这些事件中,你只关心最终状态。

何时不使用防抖

在以下情况下,防抖可能不是最佳选择:

  • 你需要在特定时间段内保证执行(改用节流
  • 你不能错过任何执行(改用队列

TanStack Pacer 中的防抖

TanStack Pacer 提供同步和异步防抖。本指南介绍同步 Debouncer 类和 debounce 函数。有关异步防抖,请参阅异步防抖指南

debounce 的基本用法

debounce 函数是向任何函数添加防抖的最简单方法:

ts
import { debounce } from '@tanstack/pacer'

// 防抖搜索输入以等待用户停止输入
const debouncedSearch = debounce(
  (searchTerm: string) => performSearch(searchTerm),
  {
    wait: 500, // 最后一次按键后等待 500 毫秒
  }
)

searchInput.addEventListener('input', (e) => {
  debouncedSearch(e.target.value)
})
import { debounce } from '@tanstack/pacer'

// 防抖搜索输入以等待用户停止输入
const debouncedSearch = debounce(
  (searchTerm: string) => performSearch(searchTerm),
  {
    wait: 500, // 最后一次按键后等待 500 毫秒
  }
)

searchInput.addEventListener('input', (e) => {
  debouncedSearch(e.target.value)
})

Debouncer 类的高级用法

要对防抖行为进行更多控制,可以直接使用 Debouncer 类:

ts
import { Debouncer } from '@tanstack/pacer'

const searchDebouncer = new Debouncer(
  (searchTerm: string) => performSearch(searchTerm),
  { wait: 500 }
)

// 获取有关当前状态的信息
console.log(searchDebouncer.getExecutionCount()) // 成功执行的次数
console.log(searchDebouncer.getIsPending()) // 是否有待处理的调用

// 动态更新选项
searchDebouncer.setOptions({ wait: 1000 }) // 增加等待时间

// 取消待处理的执行
searchDebouncer.cancel()
import { Debouncer } from '@tanstack/pacer'

const searchDebouncer = new Debouncer(
  (searchTerm: string) => performSearch(searchTerm),
  { wait: 500 }
)

// 获取有关当前状态的信息
console.log(searchDebouncer.getExecutionCount()) // 成功执行的次数
console.log(searchDebouncer.getIsPending()) // 是否有待处理的调用

// 动态更新选项
searchDebouncer.setOptions({ wait: 1000 }) // 增加等待时间

// 取消待处理的执行
searchDebouncer.cancel()

前沿和后沿执行

同步防抖器支持前沿和后沿执行:

ts
const debouncedFn = debounce(fn, {
  wait: 500,
  leading: true,   // 首次调用时执行
  trailing: true,  // 等待期后执行
})
const debouncedFn = debounce(fn, {
  wait: 500,
  leading: true,   // 首次调用时执行
  trailing: true,  // 等待期后执行
})
  • leading: true - 函数在首次调用时立即执行
  • leading: false (默认) - 首次调用启动等待计时器
  • trailing: true (默认) - 函数在等待期后执行
  • trailing: false - 等待期后不执行

常见模式:

  • { leading: false, trailing: true } - 默认,等待后执行
  • { leading: true, trailing: false } - 立即执行,忽略后续调用
  • { leading: true, trailing: true } - 在首次调用和等待后都执行

最大等待时间

TanStack Pacer Debouncer 特意没有像其他防抖库那样的 maxWait 选项。如果你需要让执行在更分散的时间段内运行,请考虑改用节流技术。

启用/禁用

Debouncer 类通过 enabled 选项支持启用/禁用。使用 setOptions 方法,可以随时启用/禁用防抖器:

ts
const debouncer = new Debouncer(fn, { wait: 500, enabled: false }) // 默认禁用
debouncer.setOptions({ enabled: true }) // 随时启用
const debouncer = new Debouncer(fn, { wait: 500, enabled: false }) // 默认禁用
debouncer.setOptions({ enabled: true }) // 随时启用

enabled 选项也可以是一个返回布尔值的函数,允许根据运行时条件动态启用/禁用:

ts
const debouncer = new Debouncer(fn, {
  wait: 500,
  enabled: (debouncer) => {
    return debouncer.getExecutionCount() < 10 // 执行 10 次后禁用
  }
})
const debouncer = new Debouncer(fn, {
  wait: 500,
  enabled: (debouncer) => {
    return debouncer.getExecutionCount() < 10 // 执行 10 次后禁用
  }
})

如果你正在使用框架适配器,其中防抖器选项是响应式的,则可以将 enabled 选项设置为条件值以动态启用/禁用防抖器:

ts
// React 示例
const debouncer = useDebouncer(
  setSearch, 
  { wait: 500, enabled: searchInput.value.length > 3 } // 如果使用支持响应式选项的框架适配器,则根据输入长度启用/禁用
)
// React 示例
const debouncer = useDebouncer(
  setSearch, 
  { wait: 500, enabled: searchInput.value.length > 3 } // 如果使用支持响应式选项的框架适配器,则根据输入长度启用/禁用
)

动态选项

Debouncer 中的几个选项通过接收防抖器实例的回调函数支持动态值:

ts
const debouncer = new Debouncer(fn, {
  // 根据执行计数动态调整等待时间
  wait: (debouncer) => {
    return debouncer.getExecutionCount() * 100 // 每次执行增加等待时间
  },
  // 根据执行计数动态调整启用状态
  enabled: (debouncer) => {
    return debouncer.getExecutionCount() < 10 // 执行 10 次后禁用
  }
})
const debouncer = new Debouncer(fn, {
  // 根据执行计数动态调整等待时间
  wait: (debouncer) => {
    return debouncer.getExecutionCount() * 100 // 每次执行增加等待时间
  },
  // 根据执行计数动态调整启用状态
  enabled: (debouncer) => {
    return debouncer.getExecutionCount() < 10 // 执行 10 次后禁用
  }
})

以下选项支持动态值:

  • enabled:可以是布尔值或返回布尔值的函数
  • wait:可以是数字或返回数字的函数

这允许实现适应运行时条件的复杂防抖行为。

回调选项

同步 Debouncer 支持以下回调:

ts
const debouncer = new Debouncer(fn, {
  wait: 500,
  onExecute: (debouncer) => {
    // 每次成功执行后调用
    console.log('函数已执行', debouncer.getExecutionCount())
  }
})
const debouncer = new Debouncer(fn, {
  wait: 500,
  onExecute: (debouncer) => {
    // 每次成功执行后调用
    console.log('函数已执行', debouncer.getExecutionCount())
  }
})

onExecute 回调在防抖函数每次成功执行后调用,可用于跟踪执行、更新 UI 状态或执行清理操作。


有关异步防抖(例如 API 调用、异步操作),请参阅异步防抖指南