框架
版本
Debouncer API 参考
Throttler 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 调用成功:', limiter.getExecutionCount())
    },
    onReject: (limiter) => {
      console.log(`已超出速率限制。请在 ${limiter.getMsUntilNextWindow()} 毫秒后重试`)
    },
    onError: (error, limiter) => {
      console.error('API 调用失败:', error)
    }
  }
)

// 用法
try {
  const result = await rateLimitedApi('123')
  // 处理成功的结果
} catch (error) {
  // 如果未提供 onError 处理程序,则处理错误
  console.error('API 调用失败:', 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 调用成功:', limiter.getExecutionCount())
    },
    onReject: (limiter) => {
      console.log(`已超出速率限制。请在 ${limiter.getMsUntilNextWindow()} 毫秒后重试`)
    },
    onError: (error, limiter) => {
      console.error('API 调用失败:', error)
    }
  }
)

// 用法
try {
  const result = await rateLimitedApi('123')
  // 处理成功的结果
} catch (error) {
  // 如果未提供 onError 处理程序,则处理错误
  console.error('API 调用失败:', error)
}

与同步速率限制的主要区别

1. 返回值处理

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

2. 错误处理

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

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

3. 不同的回调

AsyncRateLimiter 支持以下回调:

  • onSuccess:每次成功执行后调用,提供结果和速率限制器实例
  • onSettled:每次执行(成功或失败)后调用,提供速率限制器实例
  • onError:如果异步函数抛出错误,则调用,同时提供错误和速率限制器实例

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

示例:

ts
const asyncLimiter = new AsyncRateLimiter(async (id) => {
  await saveToAPI(id)
}, {
  limit: 5,
  window: 1000,
  onExecute: (rateLimiter) => {
    // 每次成功执行后调用
    console.log('异步函数已执行', rateLimiter.getExecutionCount())
  },
  onReject: (rateLimiter) => {
    // 当执行被拒绝时调用
    console.log(`已超出速率限制。请在 ${rateLimiter.getMsUntilNextWindow()} 毫秒后重试`)
  },
  onError: (error) => {
    // 如果异步函数抛出错误,则调用
    console.error('异步函数失败:', error)
  }
})
const asyncLimiter = new AsyncRateLimiter(async (id) => {
  await saveToAPI(id)
}, {
  limit: 5,
  window: 1000,
  onExecute: (rateLimiter) => {
    // 每次成功执行后调用
    console.log('异步函数已执行', rateLimiter.getExecutionCount())
  },
  onReject: (rateLimiter) => {
    // 当执行被拒绝时调用
    console.log(`已超出速率限制。请在 ${rateLimiter.getMsUntilNextWindow()} 毫秒后重试`)
  },
  onError: (error) => {
    // 如果异步函数抛出错误,则调用
    console.error('异步函数失败:', error)
  }
})

4. 顺序执行

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

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

动态选项和启用/禁用

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

框架适配器

每个框架适配器都提供了一些钩子,这些钩子构建在核心异步速率限制功能之上,以与框架的状态管理系统集成。每个框架都有诸如 createAsyncRateLimiteruseAsyncRateLimitedCallback 或类似的可用钩子。


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