速率限制、节流和防抖是控制函数执行频率的三种不同方法。每种技术以不同的方式阻止执行,使其成为“有损的”——这意味着当函数调用请求过于频繁时,某些函数调用将不会执行。了解何时使用每种方法对于构建高性能和可靠的应用程序至关重要。本指南将介绍 TanStack Pacer 的节流概念。
节流确保函数执行在一段时间内均匀分布。与允许在限制内爆发执行的速率限制不同,或等待活动停止的防抖不同,节流通过强制调用之间保持一致的延迟来创建更平滑的执行模式。如果您设置每秒一个执行的节流,则无论请求速度如何,调用都会均匀分布。
Throttling (one execution per 3 ticks)
Timeline: [1 second per tick]
Calls: ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
Executed: ✅ ❌ ⏳ -> ✅ ❌ ❌ ❌ ✅ ✅
[=================================================================]
^ Only one execution allowed per 3 ticks,
regardless of how many calls are made
[First burst] [More calls] [Spaced calls]
Execute first Execute after Execute each time
then throttle wait period wait period passes
当您需要一致、可预测的执行时间时,节流特别有效。这使其成为处理频繁事件或更新的理想选择,您希望获得平滑、受控的行为。
节流可能不是最佳选择,当
节流通常是您需要平滑、一致的执行时间时的最佳选择。它比速率限制提供更可预测的执行模式,并且比防抖提供更快的反馈。
TanStack Pacer 提供同步和异步节流。本指南涵盖同步 Throttler 类和 throttle 函数。有关异步节流,请参阅 异步节流指南。
throttle 函数是将节流添加到任何函数的 simplest 方法
import { throttle } from '@tanstack/pacer'
// Throttle UI updates to once every 200ms
const throttledUpdate = throttle(
(value: number) => updateProgressBar(value),
{
wait: 200,
}
)
// In a rapid loop, only executes every 200ms
for (let i = 0; i < 100; i++) {
throttledUpdate(i) // Many calls get throttled
}
注意: 当使用 React 时,为了更好地与 React 的生命周期集成和自动清理,请优先使用 useThrottledCallback 钩子,而不是 throttle 函数。
为了更精细地控制节流行为,您可以使用 Throttler 类直接使用
import { Throttler } from '@tanstack/pacer'
const updateThrottler = new Throttler(
(value: number) => updateProgressBar(value),
{ wait: 200 }
)
// Access current state via TanStack Store
console.log(updateThrottler.store.state.executionCount) // Number of successful executions
console.log(updateThrottler.store.state.lastExecutionTime) // Timestamp of last execution
console.log(updateThrottler.store.state.isPending) // Whether execution is pending
console.log(updateThrottler.store.state.status) // Current execution status
// Cancel any pending execution
updateThrottler.cancel()
// Flush pending execution immediately
updateThrottler.flush()
同步节流器支持前沿和尾随执行
const throttledFn = throttle(fn, {
wait: 200,
leading: true, // Execute on first call (default)
trailing: true, // Execute after wait period (default)
})
常用模式
使用 throttlerOptions 在不同的 Throttler 实例之间共享常用选项
import { throttlerOptions, Throttler } from '@tanstack/pacer'
const sharedOptions = throttlerOptions({
wait: 200,
leading: true,
trailing: true
})
const throttler1 = new Throttler(fn1, { ...sharedOptions, key: 'throttler1' })
const throttler2 = new Throttler(fn2, { ...sharedOptions, wait: 300 })
Throttler 类支持通过 enabled 选项启用/禁用。使用 setOptions 方法,您可以随时启用/禁用节流器
const throttler = new Throttler(fn, { wait: 200, enabled: false }) // Disable by default
throttler.setOptions({ enabled: true }) // Enable at any time
enabled 选项也可以是一个函数,该函数返回一个布尔值,从而允许根据运行时条件动态启用/禁用。
const throttler = new Throttler(fn, {
wait: 200,
enabled: (throttler) => {
return throttler.store.state.executionCount < 50 // Disable after 50 executions
}
})
如果您正在使用具有反应性节流器选项的框架适配器,您可以将 enabled 选项设置为条件值,以随时启用/禁用节流器。但是,如果您直接使用 throttle 函数或 Throttler 类,则必须使用 setOptions 方法来更改 enabled 选项,因为传递的选项实际上是传递给 Throttler 类的构造函数的。
Throttler 中的几个选项支持通过接收节流器实例的回调函数进行动态值
const throttler = new Throttler(fn, {
// Dynamic wait time based on execution count
wait: (throttler) => {
return throttler.store.state.executionCount * 100 // Increase wait time with each execution
},
// Dynamic enabled state based on execution count
enabled: (throttler) => {
return throttler.store.state.executionCount < 50 // Disable after 50 executions
}
})
以下选项支持动态值
这允许根据运行时条件调整的复杂节流行为。
同步 Throttler 支持以下回调
const throttler = new Throttler(fn, {
wait: 200,
onExecute: (throttler) => {
// Called after each successful execution
console.log('Function executed', throttler.store.state.executionCount)
}
})
在成功执行节流函数后,将调用 onExecute 回调,使其对于跟踪执行、更新 UI 状态或执行清理操作非常有用。
节流器支持刷新待处理的执行,以立即触发它们
const throttler = new Throttler(fn, { wait: 1000 })
throttler.maybeExecute('some-arg')
console.log(throttler.store.state.isPending) // true
// Flush immediately instead of waiting
throttler.flush()
console.log(throttler.store.state.isPending) // false
Throttler 类使用 TanStack Store 进行反应式状态管理,提供对执行状态和时序信息的实时访问。所有状态都存储在 TanStack Store 中,可以通过 throttler.store.state 访问,但是,如果您正在使用 React 或 Solid 等框架适配器,您将不想从这里读取状态。相反,您将从 throttler.state 读取状态,并提供选择器回调作为 useThrottler 钩子的第三个参数,以选择加入状态跟踪,如下所示。
框架适配器支持以两种方式订阅状态更改
1. 使用 throttler.Subscribe 组件(推荐用于组件树订阅)
使用 Subscribe 组件订阅组件树深处的状态更改,而无需将选择器传递给钩子。这对于希望在子组件中订阅状态非常有用。
// Default behavior - no reactive state subscriptions at hook level
const throttler = useThrottler(fn, { wait: 200 })
// Subscribe to state changes deep in component tree using Subscribe component
<throttler.Subscribe selector={(state) => ({ isPending: state.isPending })}>
{(state) => (
<div>{state.isPending ? 'Waiting...' : 'Ready'}</div>
)}
</throttler.Subscribe>
2. 使用 selector 参数(用于钩子级别订阅)
selector 参数允许您指定哪些状态更改将触发钩子级别上的反应式更新,从而通过在发生不相关的状态更改时防止不必要的更新来优化性能。
默认情况下,throttler.state 为空({}),因为选择器默认情况下为空。 这是来自 TanStack Store useStore 的反应式状态存储的位置。您必须通过提供选择器函数来选择加入状态跟踪。
// Default behavior - no reactive state subscriptions
const throttler = useThrottler(fn, { wait: 200 })
console.log(throttler.state) // {}
// Opt-in to re-render when isPending changes
const throttler = useThrottler(
fn,
{ wait: 200 },
(state) => ({ isPending: state.isPending })
)
console.log(throttler.state.isPending) // Reactive value
// Multiple state properties
const throttler = useThrottler(
fn,
{ wait: 200 },
(state) => ({
isPending: state.isPending,
executionCount: state.executionCount,
status: state.status
})
)
您可以在创建节流器时提供初始状态值。这通常用于从持久存储恢复状态
// Load initial state from localStorage
const savedState = localStorage.getItem('throttler-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const throttler = new Throttler(fn, {
wait: 200,
initialState
})
Store 是响应式的并支持订阅
const throttler = new Throttler(fn, { wait: 200 })
// Subscribe to state changes
const unsubscribe = throttler.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
注意: 当使用框架适配器时,这是不必要的,因为底层的 useStore 钩子已经这样做了。您还可以导入并使用 useStore 来自 TanStack Store,以将 throttler.store.state 转换为具有自定义选择器的反应式状态,只要您需要,就可以在任何地方使用。
ThrottlerState 包括
每个框架适配器都在节流器类周围构建方便的钩子和函数。像 useThrottler 或 createThrottler 这样的钩子是小的包装器,可以减少您自己代码中一些常见用例所需的样板代码。
对于异步节流(例如,API 调用、异步操作),请参阅 异步节流指南。