tanstack-pacer
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOverview
概述
TanStack Pacer provides a unified, type-safe toolkit for controlling function execution timing. It offers class-based APIs, factory functions, and React hooks for debouncing, throttling, rate limiting, queuing, and batching.
Core:
React:
Status: Beta
@tanstack/pacer@tanstack/react-pacerTanStack Pacer 提供一套统一的、类型安全的工具集,用于控制函数执行时机。它支持基于类的API、工厂函数以及React hooks,可实现防抖、节流、速率限制、任务排队和批量处理功能。
核心包:
React适配包:
状态: Beta版本
@tanstack/pacer@tanstack/react-pacerInstallation
安装
bash
npm install @tanstack/pacer
npm install @tanstack/react-pacer # React hooksbash
npm install @tanstack/pacer
npm install @tanstack/react-pacer # React hooksDebouncing
防抖
Delays execution until after a period of inactivity.
延迟函数执行,直到一段无操作期结束后才触发。
Class API
类API
typescript
import { Debouncer } from '@tanstack/pacer'
const debouncer = new Debouncer(
(query: string) => fetchSearchResults(query),
{
wait: 300, // ms of inactivity before execution
leading: false, // Execute on leading edge (default: false)
trailing: true, // Execute on trailing edge (default: true)
maxWait: 1000, // Force execution after 1s of continuous calls
enabled: true,
onExecute: (result) => console.log(result),
}
)
debouncer.maybeExecute('search term')
debouncer.cancel()
debouncer.getExecutionCount()
debouncer.setOptions({ wait: 500 }) // Dynamic reconfigurationtypescript
import { Debouncer } from '@tanstack/pacer'
const debouncer = new Debouncer(
(query: string) => fetchSearchResults(query),
{
wait: 300, // 无操作后等待执行的毫秒数
leading: false, // 在前缘触发执行(默认:false)
trailing: true, // 在后缘触发执行(默认:true)
maxWait: 1000, // 连续调用时,强制在1秒后执行
enabled: true,
onExecute: (result) => console.log(result),
}
)
debouncer.maybeExecute('search term')
debouncer.cancel()
debouncer.getExecutionCount()
debouncer.setOptions({ wait: 500 }) // 动态重新配置Factory Function
工厂函数
typescript
import { debounce } from '@tanstack/pacer'
const debouncedSearch = debounce(
(query: string) => fetchResults(query),
{ wait: 300 }
)
debouncedSearch('term')
debouncedSearch.cancel()typescript
import { debounce } from '@tanstack/pacer'
const debouncedSearch = debounce(
(query: string) => fetchResults(query),
{ wait: 300 }
)
debouncedSearch('term')
debouncedSearch.cancel()React Hooks
React Hooks
typescript
import {
useDebouncer,
useDebouncedCallback,
useDebouncedState,
useDebouncedValue,
} from '@tanstack/react-pacer'
// Full debouncer instance
const debouncer = useDebouncer(fn, { wait: 300 })
// Simple debounced function
const debouncedFn = useDebouncedCallback(fn, { wait: 300 })
// Debounced state management
const [debouncedValue, setValue] = useDebouncedState(initialValue, { wait: 300 })
// Debounced reactive value
const debouncedValue = useDebouncedValue(reactiveValue, { wait: 300 })typescript
import {
useDebouncer,
useDebouncedCallback,
useDebouncedState,
useDebouncedValue,
} from '@tanstack/react-pacer'
// 完整的防抖实例
const debouncer = useDebouncer(fn, { wait: 300 })
// 简易防抖函数
const debouncedFn = useDebouncedCallback(fn, { wait: 300 })
// 防抖状态管理
const [debouncedValue, setValue] = useDebouncedState(initialValue, { wait: 300 })
// 防抖响应式值
const debouncedValue = useDebouncedValue(reactiveValue, { wait: 300 })Throttling
节流
Limits execution to at most once per interval.
限制函数在指定时间间隔内最多执行一次。
Class API
类API
typescript
import { Throttler } from '@tanstack/pacer'
const throttler = new Throttler(
(position: { x: number; y: number }) => updatePosition(position),
{
wait: 100, // Minimum interval between executions
leading: true, // Execute immediately on first call (default: true)
trailing: true, // Execute after interval with last args (default: true)
enabled: true,
onExecute: (result) => console.log(result),
}
)
throttler.maybeExecute({ x: 100, y: 200 })
throttler.cancel()typescript
import { Throttler } from '@tanstack/pacer'
const throttler = new Throttler(
(position: { x: number; y: number }) => updatePosition(position),
{
wait: 100, // 两次执行的最小间隔毫秒数
leading: true, // 首次调用立即执行(默认:true)
trailing: true, // 间隔结束后使用最后一次参数执行(默认:true)
enabled: true,
onExecute: (result) => console.log(result),
}
)
throttler.maybeExecute({ x: 100, y: 200 })
throttler.cancel()React Hooks
React Hooks
typescript
import {
useThrottler,
useThrottledCallback,
useThrottledState,
useThrottledValue,
} from '@tanstack/react-pacer'
const throttledFn = useThrottledCallback(handleScroll, { wait: 100 })
const [throttledPos, setPos] = useThrottledState({ x: 0, y: 0 }, { wait: 100 })typescript
import {
useThrottler,
useThrottledCallback,
useThrottledState,
useThrottledValue,
} from '@tanstack/react-pacer'
const throttledFn = useThrottledCallback(handleScroll, { wait: 100 })
const [throttledPos, setPos] = useThrottledState({ x: 0, y: 0 }, { wait: 100 })Rate Limiting
速率限制
Controls execution with a maximum count within a time window.
控制在指定时间窗口内的最大执行次数。
Class API
类API
typescript
import { RateLimiter } from '@tanstack/pacer'
const limiter = new RateLimiter(
async (endpoint: string) => fetch(endpoint).then(r => r.json()),
{
limit: 10, // Max executions per window
window: 60000, // Time window in ms (60s)
enabled: true,
onExecute: (result) => console.log(result),
onReject: (...args) => console.warn('Rate limited:', args),
}
)
limiter.maybeExecute('/api/data') // Rejected if limit exceeded
limiter.getExecutionCount()
limiter.getRejectionCount()typescript
import { RateLimiter } from '@tanstack/pacer'
const limiter = new RateLimiter(
async (endpoint: string) => fetch(endpoint).then(r => r.json()),
{
limit: 10, // 每个时间窗口内的最大执行次数
window: 60000, // 时间窗口大小(毫秒,60秒)
enabled: true,
onExecute: (result) => console.log(result),
onReject: (...args) => console.warn('Rate limited:', args),
}
)
limiter.maybeExecute('/api/data') // 超过限制时会被拒绝
limiter.getExecutionCount()
limiter.getRejectionCount()React Hooks
React Hooks
typescript
import {
useRateLimiter,
useRateLimitedCallback,
useRateLimitedState,
useRateLimitedValue,
} from '@tanstack/react-pacer'
const rateLimitedFn = useRateLimitedCallback(apiCall, { limit: 5, window: 1000 })typescript
import {
useRateLimiter,
useRateLimitedCallback,
useRateLimitedState,
useRateLimitedValue,
} from '@tanstack/react-pacer'
const rateLimitedFn = useRateLimitedCallback(apiCall, { limit: 5, window: 1000 })Queuing
任务排队
Sequential execution with configurable concurrency.
typescript
import { Queue } from '@tanstack/pacer'
const queue = new Queue({
concurrency: 1, // Max concurrent tasks
started: true, // Start processing immediately
})
queue.add(() => uploadFile(file1))
queue.add(() => uploadFile(file2))
queue.start()
queue.pause()
queue.clear()
queue.getSize() // Pending count
queue.getPending() // Currently executing count支持可配置并发数的顺序执行。
typescript
import { Queue } from '@tanstack/pacer'
const queue = new Queue({
concurrency: 1, // 最大并发任务数
started: true, // 立即开始处理任务
})
queue.add(() => uploadFile(file1))
queue.add(() => uploadFile(file2))
queue.start()
queue.pause()
queue.clear()
queue.getSize() // 待处理任务数
queue.getPending() // 当前正在执行的任务数Batching
批量处理
Groups calls for combined processing.
typescript
import { Batcher } from '@tanstack/pacer'
const batcher = new Batcher(
(items: LogEntry[]) => sendBatchToServer(items),
{
maxSize: 50, // Auto-flush at 50 items
wait: 1000, // Auto-flush after 1s
}
)
batcher.add(logEntry) // Accumulates
batcher.flush() // Manual flush
batcher.getSize() // Current batch size
batcher.clear() // Discard batch将多次调用分组后统一处理。
typescript
import { Batcher } from '@tanstack/pacer'
const batcher = new Batcher(
(items: LogEntry[]) => sendBatchToServer(items),
{
maxSize: 50, // 达到50条数据时自动触发批量处理
wait: 1000, // 1秒后自动触发批量处理
}
)
batcher.add(logEntry) // 累积数据
batcher.flush() // 手动触发批量处理
batcher.getSize() // 当前批量数据大小
batcher.clear() // 清空批量数据Async Variants
异步变体
typescript
import { AsyncDebouncer, asyncDebounce, AsyncThrottler, asyncThrottle } from '@tanstack/pacer'
const asyncDebouncer = new AsyncDebouncer(
async (query: string) => {
const response = await fetch(`/api/search?q=${query}`)
return response.json()
},
{ wait: 300 }
)
// React async hooks
import { useAsyncDebouncer, useAsyncThrottler } from '@tanstack/react-pacer'typescript
import { AsyncDebouncer, asyncDebounce, AsyncThrottler, asyncThrottle } from '@tanstack/pacer'
const asyncDebouncer = new AsyncDebouncer(
async (query: string) => {
const response = await fetch(`/api/search?q=${query}`)
return response.json()
},
{ wait: 300 }
)
// React 异步Hooks
import { useAsyncDebouncer, useAsyncThrottler } from '@tanstack/react-pacer'Choosing the Right Utility
选择合适的工具
| Scenario | Utility | Why |
|---|---|---|
| Search input | Debouncer | Wait for user to stop typing |
| Scroll events | Throttler | Periodic updates during activity |
| API protection | RateLimiter | Hard limit on call frequency |
| File uploads | Queue | Sequential processing |
| Analytics events | Batcher | Group for efficiency |
| Network requests | AsyncDebouncer | Handle abort/retry |
| 场景 | 工具 | 原因 |
|---|---|---|
| 搜索输入 | Debouncer | 等待用户停止输入后执行 |
| 滚动事件 | Throttler | 在用户操作期间定期更新 |
| API调用保护 | RateLimiter | 严格限制调用频率 |
| 文件上传 | Queue | 顺序处理任务 |
| 分析事件上报 | Batcher | 分组处理提升效率 |
| 网络请求 | AsyncDebouncer | 处理中断/重试逻辑 |
Leading vs Trailing Edge
前缘执行 vs 后缘执行
- Leading (): Execute immediately, suppress until wait expires. Good for button clicks.
leading: true - Trailing (): Execute after activity stops. Good for search inputs.
trailing: true - Both: Execute immediately AND after final wait. Good for scroll throttling.
- 前缘执行 ():立即执行函数,在等待期内抑制后续调用。适用于按钮点击场景。
leading: true - 后缘执行 ():在用户操作停止后执行函数。适用于搜索输入场景。
trailing: true - 两者启用:立即执行且在最终等待期后再次执行。适用于滚动节流场景。
Best Practices
最佳实践
- Use with debouncing to guarantee execution during continuous activity
maxWait - Use async variants for network requests (handle abort/cancellation)
- React hooks handle cleanup automatically - no manual teardown needed
- Use for dynamic reconfiguration (e.g., reducing wait for power users)
setOptions - Compose utilities for complex scenarios (rate-limited queue)
- Use on RateLimiter to inform users when they're rate limited
onReject
- 防抖时使用:确保在连续操作期间函数仍能被执行
maxWait - 使用异步变体:处理网络请求时支持中断/取消
- React Hooks自动清理:无需手动销毁实例
- 使用:实现动态配置(例如为高级用户缩短等待时间)
setOptions - 组合工具:应对复杂场景(如带速率限制的任务队列)
- RateLimiter中使用:告知用户已触发速率限制
onReject
Common Pitfalls
常见误区
- Using debounce when you need throttle (debounce waits for inactivity, throttle guarantees periodic execution)
- Not using with debounce for long-running continuous events
maxWait - Creating new instances on every render (use hooks or module-level)
- Forgetting cleanup in non-React environments (call )
cancel()
- 需要节流时误用防抖(防抖等待无操作后执行,节流保证定期执行)
- 防抖时未设置处理长时间连续事件
maxWait - 每次渲染时创建新实例(应使用Hooks或模块级实例)
- 在非React环境中忘记清理(需调用)
cancel()