文档
CodeRabbit
Cloudflare
AG Grid
Netlify
Neon
WorkOS
Clerk
Convex
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
Netlify
Neon
WorkOS
Clerk
Convex
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
防抖器 API 参考
节流器 API 参考
速率限制器 API 参考
队列 API 参考
批处理器 API 参考
指南

节流指南

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

节流概念

节流确保函数执行在一段时间内均匀分布。与允许在限制内爆发执行的速率限制不同,或等待活动停止的防抖不同,节流通过强制调用之间保持一致的延迟来创建更平滑的执行模式。如果您设置每秒一个执行的节流,则无论请求速度如何,调用都会均匀分布。

节流可视化

text
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 中的节流

TanStack Pacer 提供同步和异步节流。本指南涵盖同步 Throttler 类和 throttle 函数。有关异步节流,请参阅 异步节流指南

使用 throttle 的基本用法

throttle 函数是将节流添加到任何函数的 simplest 方法

ts
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 类的进阶用法

为了更精细地控制节流行为,您可以使用 Throttler 类直接使用

ts
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()

前沿和尾随执行

同步节流器支持前沿和尾随执行

ts
const throttledFn = throttle(fn, {
  wait: 200,
  leading: true,   // Execute on first call (default)
  trailing: true,  // Execute after wait period (default)
})
  • leading: true (默认) - 在第一次调用时立即执行
  • leading: false - 跳过第一次调用,等待尾随执行
  • trailing: true (默认) - 在等待期后执行最后一次调用
  • trailing: false - 如果在等待期内,则跳过最后一次调用

常用模式

  • { leading: true, trailing: true } - 默认,响应速度最快
  • { leading: false, trailing: true } - 延迟所有执行
  • { leading: true, trailing: false } - 跳过排队的执行

在实例之间共享选项

使用 throttlerOptions 在不同的 Throttler 实例之间共享常用选项

ts
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 方法,您可以随时启用/禁用节流器

ts
const throttler = new Throttler(fn, { wait: 200, enabled: false }) // Disable by default
throttler.setOptions({ enabled: true }) // Enable at any time

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

ts
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 中的几个选项支持通过接收节流器实例的回调函数进行动态值

ts
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
  }
})

以下选项支持动态值

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

这允许根据运行时条件调整的复杂节流行为。

回调选项

同步 Throttler 支持以下回调

ts
const throttler = new Throttler(fn, {
  wait: 200,
  onExecute: (throttler) => {
    // Called after each successful execution
    console.log('Function executed', throttler.store.state.executionCount)
  }
})

在成功执行节流函数后,将调用 onExecute 回调,使其对于跟踪执行、更新 UI 状态或执行清理操作非常有用。

刷新待定执行

节流器支持刷新待处理的执行,以立即触发它们

ts
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 组件订阅组件树深处的状态更改,而无需将选择器传递给钩子。这对于希望在子组件中订阅状态非常有用。

tsx
// 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 的反应式状态存储的位置。您必须通过提供选择器函数来选择加入状态跟踪。

ts
// 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
  })
)

初始状态

您可以在创建节流器时提供初始状态值。这通常用于从持久存储恢复状态

ts
// 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 是响应式的并支持订阅

ts
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 包括

  • executionCount: 已完成的函数执行次数
  • isPending:节流器是否正在等待超时以触发执行
  • lastArgs: 上次调用 maybeExecute 的参数
  • lastExecutionTime:最后一次函数执行的时间戳(毫秒)
  • maybeExecuteCount: maybeExecute 被调用的次数
  • nextExecutionTime:下一次执行可以发生的时间戳(毫秒)
  • status: 当前执行状态('disabled' | 'idle' | 'pending')

框架适配器

每个框架适配器都在节流器类周围构建方便的钩子和函数。像 useThrottlercreateThrottler 这样的钩子是小的包装器,可以减少您自己代码中一些常见用例所需的样板代码。


对于异步节流(例如,API 调用、异步操作),请参阅 异步节流指南