速率限制、节流和防抖是三种不同的控制函数执行频率的方法。每种技术以不同的方式阻止执行,使其成为“有损的”——这意味着当函数调用过于频繁时,某些函数调用将不会执行。了解何时使用每种方法对于构建高性能和可靠的应用程序至关重要。本指南将介绍 TanStack Pacer 的防抖概念。
防抖是一种技术,它会延迟函数的执行,直到发生指定的一段时间的非活动状态。与速率限制(允许在限制内爆发执行)或节流(确保均匀间隔的执行)不同,防抖会将多次快速函数调用合并为单个执行,该执行仅在调用停止后发生。这使得防抖非常适合处理事件爆发,在这些事件中,您只关心活动稳定后的最终状态。
Debouncing (wait: 3 ticks)
Timeline: [1 second per tick]
Calls: ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
Executed: ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ⏳ -> ✅ ❌ ⏳ -> ✅
[=================================================================]
^ Executes here after
3 ticks of no calls
[Burst of calls] [More calls] [Wait] [New burst]
No execution Resets timer [Delayed Execute] [Wait] [Delayed Execute]
当您希望在活动“暂停”后才采取行动时,防抖特别有效。这使其非常适合处理用户输入或其他快速触发的事件,在这些事件中,您只关心最终状态。
防抖可能不是最佳选择,当
TanStack Pacer 提供同步和异步防抖。本指南涵盖同步 Debouncer 类和 debounce 函数。有关异步防抖,请参阅 异步防抖指南。
debounce 函数是将防抖添加到任何函数的 simplest 方法
import { debounce } from '@tanstack/pacer'
// Debounce search input to wait for user to stop typing
const debouncedSearch = debounce(
(searchTerm: string) => performSearch(searchTerm),
{
wait: 500, // Wait 500ms after last keystroke
}
)
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value)
})
注意:在使用 React 时,请优先使用 useDebouncedCallback 钩子,而不是 debounce 函数,以便更好地与 React 的生命周期集成和自动清理。
为了更好地控制防抖行为,您可以使用 Debouncer 类
import { Debouncer } from '@tanstack/pacer'
const searchDebouncer = new Debouncer(
(searchTerm: string) => performSearch(searchTerm),
{ wait: 500 }
)
// Access current state via TanStack Store
console.log(searchDebouncer.store.state.executionCount) // Number of successful executions
console.log(searchDebouncer.store.state.isPending) // Whether a call is pending
console.log(searchDebouncer.store.state.status) // Current execution status
// Update options dynamically
searchDebouncer.setOptions({ wait: 1000 }) // Increase wait time
// Cancel pending execution
searchDebouncer.cancel()
// Flush pending execution immediately
searchDebouncer.flush()
同步防抖器支持前沿和尾随执行
const debouncedFn = debounce(fn, {
wait: 500,
leading: true, // Execute on first call
trailing: true, // Execute after wait period
})
常用模式
TanStack Pacer Debouncer 故意没有像其他防抖库那样的 maxWait 选项。如果您需要在更分散的时间段内让执行运行,请考虑使用 节流 技术。
使用 debouncerOptions 在不同的 Debouncer 实例之间共享常用选项
import { debouncerOptions, Debouncer } from '@tanstack/pacer'
const sharedOptions = debouncerOptions({
wait: 500,
leading: false,
trailing: true
})
const debouncer1 = new Debouncer(fn1, { ...sharedOptions, key: 'debouncer1' })
const debouncer2 = new Debouncer(fn2, { ...sharedOptions, wait: 1000 })
Debouncer 类支持通过 enabled 选项启用/禁用。使用 setOptions 方法,您可以随时启用/禁用防抖器
const debouncer = new Debouncer(fn, { wait: 500, enabled: false }) // Disable by default
debouncer.setOptions({ enabled: true }) // Enable at any time
enabled 选项也可以是一个函数,该函数返回一个布尔值,从而允许根据运行时条件动态启用/禁用。
const debouncer = new Debouncer(fn, {
wait: 500,
enabled: (debouncer) => {
return debouncer.store.state.executionCount < 10 // Disable after 10 executions
}
})
如果您正在使用具有反应式选项的框架适配器,您可以将 enabled 选项设置为条件值,以随时启用/禁用防抖器
// React example
const debouncer = useDebouncer(
setSearch,
{ wait: 500, enabled: searchInput.value.length > 3 } // Enable/disable based on input length IF using a framework adapter that supports reactive options
)
防抖器中的几个选项支持通过接收防抖器实例的回调函数动态值
const debouncer = new Debouncer(fn, {
// Dynamic wait time based on execution count
wait: (debouncer) => {
return debouncer.store.state.executionCount * 100 // Increase wait time with each execution
},
// Dynamic enabled state based on execution count
enabled: (debouncer) => {
return debouncer.store.state.executionCount < 10 // Disable after 10 executions
}
})
以下选项支持动态值
这允许根据运行时条件调整的复杂防抖行为。
同步 Debouncer 支持以下回调
const debouncer = new Debouncer(fn, {
wait: 500,
onExecute: (debouncer) => {
// Called after each successful execution
console.log('Function executed', debouncer.store.state.executionCount)
}
})
每次成功执行防抖函数后,都会调用 onExecute 回调,使其对于跟踪执行、更新 UI 状态或执行清理操作非常有用。
防抖器支持刷新待处理的执行,以立即触发它们
const debouncer = new Debouncer(fn, { wait: 1000 })
debouncer.maybeExecute('some-arg')
console.log(debouncer.store.state.isPending) // true
// Flush immediately instead of waiting
debouncer.flush()
console.log(debouncer.store.state.isPending) // false
Debouncer 类使用 TanStack Store 进行反应式状态管理,提供对执行状态和统计信息的实时访问。所有状态都存储在 TanStack Store 中,可以通过 debouncer.store.state 访问,但是,如果您正在使用 React 或 Solid 等框架适配器,您将不想从这里读取状态。相反,您将从 debouncer.state 读取状态,并提供选择器回调作为 useDebouncer 钩子的第三个参数,以选择加入状态跟踪,如下所示。
框架适配器支持以两种方式订阅状态更改
1. 使用 debouncer.Subscribe 组件(推荐用于组件树订阅)
使用 Subscribe 组件订阅组件树深处的状态更改,而无需将选择器传递给钩子。这对于希望在子组件中订阅状态非常有用。
// Default behavior - no reactive state subscriptions at hook level
const debouncer = useDebouncer(fn, { wait: 500 })
// Subscribe to state changes deep in component tree using Subscribe component
<debouncer.Subscribe selector={(state) => ({ isPending: state.isPending })}>
{(state) => (
<div>{state.isPending ? 'Waiting...' : 'Ready'}</div>
)}
</debouncer.Subscribe>
2. 使用 selector 参数(用于钩子级别订阅)
selector 参数允许您指定哪些状态更改将触发钩子级别上的反应式更新,从而通过在发生不相关的状态更改时防止不必要的更新来优化性能。
默认情况下,debouncer.state 是空的({}),因为默认情况下选择器为空。 这是来自 TanStack Store useStore 的反应式状态存储的位置。您必须通过提供选择器函数来选择加入状态跟踪。
// Default behavior - no reactive state subscriptions
const debouncer = useDebouncer(fn, { wait: 500 })
console.log(debouncer.state) // {}
// Opt-in to re-render when isPending changes
const debouncer = useDebouncer(
fn,
{ wait: 500 },
(state) => ({ isPending: state.isPending })
)
console.log(debouncer.state.isPending) // Reactive value
// Multiple state properties
const debouncer = useDebouncer(
fn,
{ wait: 500 },
(state) => ({
isPending: state.isPending,
executionCount: state.executionCount,
status: state.status
})
)
您可以在创建防抖器时提供初始状态值。这通常用于从持久存储恢复状态
// Load initial state from localStorage
const savedState = localStorage.getItem('debouncer-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const debouncer = new Debouncer(fn, {
wait: 500,
key: 'search-debouncer',
initialState
})
Store 是响应式的并支持订阅
const debouncer = new Debouncer(fn, { wait: 500 })
// Subscribe to state changes
const unsubscribe = debouncer.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
注意:当使用框架适配器时,这是不必要的,因为底层的 useStore 钩子已经执行了此操作。您还可以导入并使用 useStore 来自 TanStack Store,以在任何必要时将 debouncer.store.state 转换为具有自定义选择器的反应式状态。
DebouncerState 包括
每个框架适配器都在防抖器类周围构建方便的钩子和函数。像 useDebouncer 或 createDebouncer 这样的钩子是小的包装器,可以减少您在一些常见用例中的代码量。
对于异步防抖(例如,API 调用、异步操作),请参阅 异步防抖指南。