框架
版本
防抖器 API 参考
节流器 API 参考
速率限制器 API 参考
队列 API 参考
批处理器 API 参考

异步速率限制指南

来自速率限制指南的所有核心概念也适用于异步速率限制。

何时使用异步速率限制

通常,您只需使用普通的同步速率限制器,它就可以与异步函数一起工作。但对于高级用例,例如想要使用速率限制函数的返回值(而不仅仅是调用 setState 侧效应),或将错误处理逻辑放在速率限制器中,您可以使用异步速率限制器。

TanStack Pacer 中的异步速率限制

TanStack Pacer 通过 AsyncRateLimiter 类和 asyncRateLimit 函数提供异步速率限制。

基本用法示例

下面是一个展示如何为 API 操作使用异步速率限制器的基本示例

ts
const rateLimitedApi = asyncRateLimit(
  async (id: string) => {
    const response = await fetch(`/api/data/${id}`)
    return response.json()
  },
  {
    limit: 5,
    window: 1000,
    onExecute: (limiter) => {
      console.log('API call succeeded:', limiter.store.state.successCount)
    },
    onReject: (limiter) => {
      console.log(`Rate limit exceeded. Try again in ${limiter.getMsUntilNextWindow()}ms`)
    },
    onError: (error, limiter) => {
      console.error('API call failed:', error)
    }
  }
)

// Usage
try {
  const result = await rateLimitedApi('123')
  // Handle successful result
} catch (error) {
  // Handle errors if no onError handler was provided
  console.error('API call failed:', error)
}
const rateLimitedApi = asyncRateLimit(
  async (id: string) => {
    const response = await fetch(`/api/data/${id}`)
    return response.json()
  },
  {
    limit: 5,
    window: 1000,
    onExecute: (limiter) => {
      console.log('API call succeeded:', limiter.store.state.successCount)
    },
    onReject: (limiter) => {
      console.log(`Rate limit exceeded. Try again in ${limiter.getMsUntilNextWindow()}ms`)
    },
    onError: (error, limiter) => {
      console.error('API call failed:', error)
    }
  }
)

// Usage
try {
  const result = await rateLimitedApi('123')
  // Handle successful result
} catch (error) {
  // Handle errors if no onError handler was provided
  console.error('API call failed:', error)
}

注意: 在使用 React 时,优先使用 useAsyncRateLimitedCallback hook 而不是 asyncRateLimit 函数,以更好地与 React 的生命周期集成并实现自动清理。

与同步速率限制的关键区别

1. 返回值处理

与返回布尔值表示成功的同步速率限制器不同,异步版本允许您捕获并使用速率限制函数的返回值。maybeExecute 方法返回一个 Promise,该 Promise 解析为函数的返回值,允许您等待结果并进行适当处理。

2. 错误处理

异步速率限制器提供强大的错误处理能力

  • 如果您的速率限制函数抛出错误且未提供 onError 处理程序,该错误将抛出并传播到调用者。
  • 如果您提供了 onError 处理程序,错误将被捕获并传递给处理程序,而不是被抛出。
  • 可以使用 throwOnError 选项来控制错误抛出行为
    • 当为 true 时(如果没有 onError 处理程序,则为默认值),将抛出错误
    • 当为 false 时(如果提供了 onError 处理程序,则为默认值),错误将被忽略
    • 可以显式设置以覆盖这些默认值
  • 您可以使用 limiter.store.state.errorCount 跟踪错误计数,并使用 limiter.store.state.isExecuting 检查执行状态。
  • 速率限制器会维护其状态,并在发生错误后继续使用。
  • 速率限制拒绝(当超出限制时)与执行错误分开处理,通过 onReject 处理程序。

3. 不同的回调函数

AsyncRateLimiter 支持以下回调函数:

  • onSuccess:每次成功执行后调用,提供结果、执行的参数以及速率限制器实例。
  • onSettled:每次执行(成功或失败)后调用,提供执行的参数以及速率限制器实例。
  • onError:如果异步函数抛出错误,则调用,提供错误、导致错误的参数以及速率限制器实例。

异步和同步速率限制器都支持 onReject 回调函数,用于处理被阻止的执行。

示例

ts
const asyncLimiter = new AsyncRateLimiter(async (id) => {
  await saveToAPI(id)
}, {
  limit: 5,
  window: 1000,
  onExecute: (rateLimiter) => {
    // Called after each successful execution
    console.log('Async function executed', rateLimiter.store.state.successCount)
  },
  onReject: (rateLimiter) => {
    // Called when an execution is rejected
    console.log(`Rate limit exceeded. Try again in ${rateLimiter.getMsUntilNextWindow()}ms`)
  },
  onError: (error) => {
    // Called if the async function throws an error
    console.error('Async function failed:', error)
  }
})
const asyncLimiter = new AsyncRateLimiter(async (id) => {
  await saveToAPI(id)
}, {
  limit: 5,
  window: 1000,
  onExecute: (rateLimiter) => {
    // Called after each successful execution
    console.log('Async function executed', rateLimiter.store.state.successCount)
  },
  onReject: (rateLimiter) => {
    // Called when an execution is rejected
    console.log(`Rate limit exceeded. Try again in ${rateLimiter.getMsUntilNextWindow()}ms`)
  },
  onError: (error) => {
    // Called if the async function throws an error
    console.error('Async function failed:', error)
  }
})

4. 顺序执行

由于速率限制器的 maybeExecute 方法返回一个 Promise,您可以选择在开始下一次执行之前等待每次执行。这让您能够控制执行顺序,并确保每次调用都处理最新的数据。这在处理依赖于先前调用结果的操作或在维护数据一致性至关重要时特别有用。

例如,如果您正在更新用户的个人资料,然后立即获取其更新后的数据,您可以在开始获取之前等待更新操作完成。

动态选项和启用/禁用

与同步速率限制器一样,异步速率限制器支持 limitwindowenabled 的动态选项,这些选项可以是接收速率限制器实例的函数。这允许进行复杂、运行时自适应的速率限制行为。

状态管理

AsyncRateLimiter 类使用 TanStack Store 进行响应式状态管理,提供对执行状态、错误跟踪和拒绝统计的实时访问。所有状态都存储在 TanStack Store 中,可以通过 asyncLimiter.store.state 访问。但是,如果您使用的是 React 或 Solid 等框架适配器,您将不会从这里读取状态。相反,您将从 asyncLimiter.state 读取状态,并通过为 useAsyncRateLimiter hook 提供第三个参数(选择器回调)来选择加入状态跟踪,如下所示。

状态选择器(框架适配器)

框架适配器支持一个 selector 参数,允许您指定哪些状态更改将触发重新渲染。这可以通过防止不相关的状态更改发生不必要的重新渲染来优化性能。

默认情况下,rateLimiter.state 为空({}),因为选择器默认为空。 这是 TanStack Store 的响应式状态 useStore 存储的位置。您必须提供一个选择器函数来选择加入状态跟踪。

ts
// Default behavior - no reactive state subscriptions
const asyncLimiter = useAsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })
console.log(asyncLimiter.state) // {}

// Opt-in to re-render when isExecuting changes
const asyncLimiter = useAsyncRateLimiter(
  asyncFn, 
  { limit: 5, window: 1000 },
  (state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncLimiter.state.isExecuting) // Reactive value

// Multiple state properties
const asyncLimiter = useAsyncRateLimiter(
  asyncFn,
  { limit: 5, window: 1000 },
  (state) => ({
    isExecuting: state.isExecuting,
    successCount: state.successCount,
    errorCount: state.errorCount
  })
)
// Default behavior - no reactive state subscriptions
const asyncLimiter = useAsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })
console.log(asyncLimiter.state) // {}

// Opt-in to re-render when isExecuting changes
const asyncLimiter = useAsyncRateLimiter(
  asyncFn, 
  { limit: 5, window: 1000 },
  (state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncLimiter.state.isExecuting) // Reactive value

// Multiple state properties
const asyncLimiter = useAsyncRateLimiter(
  asyncFn,
  { limit: 5, window: 1000 },
  (state) => ({
    isExecuting: state.isExecuting,
    successCount: state.successCount,
    errorCount: state.errorCount
  })
)

初始状态

您可以在创建异步速率限制器时提供初始状态值。

ts
const savedState = localStorage.getItem('async-rate-limiter-state')
const initialState = savedState ? JSON.parse(savedState) : {}

const asyncLimiter = new AsyncRateLimiter(asyncFn, {
  limit: 5,
  window: 1000,
  initialState
})
const savedState = localStorage.getItem('async-rate-limiter-state')
const initialState = savedState ? JSON.parse(savedState) : {}

const asyncLimiter = new AsyncRateLimiter(asyncFn, {
  limit: 5,
  window: 1000,
  initialState
})

订阅状态更改

Store 是响应式的并支持订阅

ts
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// Subscribe to state changes
const unsubscribe = asyncLimiter.store.subscribe((state) => {
  // do something with the state like persist it to localStorage
})

// Unsubscribe when done
unsubscribe()
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// Subscribe to state changes
const unsubscribe = asyncLimiter.store.subscribe((state) => {
  // do something with the state like persist it to localStorage
})

// Unsubscribe when done
unsubscribe()

注意: 在使用框架适配器时,这没有必要,因为底层的 useStore hook 已经完成了此操作。您也可以从 TanStack Store 导入和使用 useStore,以便在需要时将 rateLimiter.store.state 转换为具有自定义选择器的响应式状态。

可用状态属性

AsyncRateLimiterState 包括:

  • errorCount:导致错误的函数执行次数。
  • executionTimes:执行发生的时间戳数组,用于速率限制计算。
  • isExecuting:速率限制的函数当前是否正在异步执行。
  • lastResult:最近一次成功函数执行的结果。
  • maybeExecuteCount: 调用 maybeExecute 的次数
  • rejectionCount:由于速率限制而被拒绝的函数执行次数。
  • settledCount:已完成(成功或有错误)的函数执行次数。
  • status:当前执行状态('disabled' | 'exceeded' | 'idle')。
  • successCount:成功完成的函数执行次数。

辅助方法

异步速率限制器提供辅助方法,这些方法根据当前状态计算值。

ts
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// These methods use the current state to compute values
console.log(asyncLimiter.getRemainingInWindow()) // Number of calls remaining in current window
console.log(asyncLimiter.getMsUntilNextWindow()) // Milliseconds until next window
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// These methods use the current state to compute values
console.log(asyncLimiter.getRemainingInWindow()) // Number of calls remaining in current window
console.log(asyncLimiter.getMsUntilNextWindow()) // Milliseconds until next window

这些方法是计算值,它们使用当前状态,不需要通过 store 访问。

框架适配器

每个框架适配器都提供基于核心异步速率限制功能构建的 hook,以集成到框架的状态管理系统中。每个框架都提供诸如 createAsyncRateLimiteruseAsyncRateLimitedCallback 或类似的 hook。


有关核心速率限制概念和同步速率限制,请参阅速率限制指南

我们的合作伙伴
Code Rabbit
Unkey
订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。

订阅 Bytes

您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。

Bytes

无垃圾邮件。您可以随时取消订阅。