速率限制、限流和防抖是控制函数执行频率的三种不同方法。每种技术都以不同的方式阻止执行,使它们“有损”——这意味着一些函数调用在请求过于频繁时不会执行。了解何时使用每种方法对于构建高性能和可靠的应用程序至关重要。本指南将介绍 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
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
函数是将限流添加到任何函数的最简单方法
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
}
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 时,请优先使用 useThrottledCallback hook 而不是 throttle 函数,以更好地集成 React 的生命周期和自动清理。
为了更好地控制限流行为,您可以直接使用 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()
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)
})
const throttledFn = throttle(fn, {
wait: 200,
leading: true, // Execute on first call (default)
trailing: true, // Execute after wait period (default)
})
常见模式
Throttler 类支持通过接收限流器实例的回调函数来启用/禁用。使用 setOptions 方法,您可以随时启用/禁用限流器
const throttler = new Throttler(fn, { wait: 200, enabled: false }) // Disable by default
throttler.setOptions({ enabled: true }) // Enable at any time
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
}
})
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
}
})
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)
}
})
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
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 hook 提供一个选择器回调作为第三个参数,以选择加入状态跟踪,如下所示。
框架适配器支持一个 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
})
)
// 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
})
// 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()
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 hook 已经完成了此操作。如果您需要,也可以导入并使用 TanStack Store 中的 useStore 将 throttler.store.state 转换为具有自定义选择器的响应式状态。
ThrottlerState 包括
每个框架适配器都围绕限流器类构建了方便的 hooks 和函数。像 useThrottler 或 createThrottler 这样的 hooks 是小的包装器,可以减少在您的代码中为一些常见用例所需的样板代码。
有关异步限流(例如 API 调用、异步操作),请参阅 异步限流指南。
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。