tanstack-pacer

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Overview

概述

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:
@tanstack/pacer
React:
@tanstack/react-pacer
Status: Beta
TanStack Pacer 提供一套统一的、类型安全的工具集,用于控制函数执行时机。它支持基于类的API、工厂函数以及React hooks,可实现防抖、节流、速率限制、任务排队和批量处理功能。
核心包:
@tanstack/pacer
React适配包:
@tanstack/react-pacer
状态: Beta版本

Installation

安装

bash
npm install @tanstack/pacer
npm install @tanstack/react-pacer  # React hooks
bash
npm install @tanstack/pacer
npm install @tanstack/react-pacer  # React hooks

Debouncing

防抖

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 reconfiguration
typescript
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

选择合适的工具

ScenarioUtilityWhy
Search inputDebouncerWait for user to stop typing
Scroll eventsThrottlerPeriodic updates during activity
API protectionRateLimiterHard limit on call frequency
File uploadsQueueSequential processing
Analytics eventsBatcherGroup for efficiency
Network requestsAsyncDebouncerHandle abort/retry
场景工具原因
搜索输入Debouncer等待用户停止输入后执行
滚动事件Throttler在用户操作期间定期更新
API调用保护RateLimiter严格限制调用频率
文件上传Queue顺序处理任务
分析事件上报Batcher分组处理提升效率
网络请求AsyncDebouncer处理中断/重试逻辑

Leading vs Trailing Edge

前缘执行 vs 后缘执行

  • Leading (
    leading: true
    ): Execute immediately, suppress until wait expires. Good for button clicks.
  • Trailing (
    trailing: true
    ): Execute after activity stops. Good for search inputs.
  • Both: Execute immediately AND after final wait. Good for scroll throttling.
  • 前缘执行 (
    leading: true
    ):立即执行函数,在等待期内抑制后续调用。适用于按钮点击场景。
  • 后缘执行 (
    trailing: true
    ):在用户操作停止后执行函数。适用于搜索输入场景。
  • 两者启用:立即执行且在最终等待期后再次执行。适用于滚动节流场景。

Best Practices

最佳实践

  1. Use
    maxWait
    with debouncing
    to guarantee execution during continuous activity
  2. Use async variants for network requests (handle abort/cancellation)
  3. React hooks handle cleanup automatically - no manual teardown needed
  4. Use
    setOptions
    for dynamic reconfiguration (e.g., reducing wait for power users)
  5. Compose utilities for complex scenarios (rate-limited queue)
  6. Use
    onReject
    on RateLimiter to inform users when they're rate limited
  1. 防抖时使用
    maxWait
    :确保在连续操作期间函数仍能被执行
  2. 使用异步变体:处理网络请求时支持中断/取消
  3. React Hooks自动清理:无需手动销毁实例
  4. 使用
    setOptions
    :实现动态配置(例如为高级用户缩短等待时间)
  5. 组合工具:应对复杂场景(如带速率限制的任务队列)
  6. RateLimiter中使用
    onReject
    :告知用户已触发速率限制

Common Pitfalls

常见误区

  • Using debounce when you need throttle (debounce waits for inactivity, throttle guarantees periodic execution)
  • Not using
    maxWait
    with debounce for long-running continuous events
  • Creating new instances on every render (use hooks or module-level)
  • Forgetting cleanup in non-React environments (call
    cancel()
    )
  • 需要节流时误用防抖(防抖等待无操作后执行,节流保证定期执行)
  • 防抖时未设置
    maxWait
    处理长时间连续事件
  • 每次渲染时创建新实例(应使用Hooks或模块级实例)
  • 在非React环境中忘记清理(需调用
    cancel()