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

异步节流指南

来自节流指南的所有核心概念同样适用于异步节流。

何时使用异步节流

通常情况下,您只需使用普通的同步节流器,它就能与异步函数协同工作。但对于高级用例,例如想要使用节流函数的返回值(而不仅仅是调用 setState 副作用)或将错误处理逻辑放在节流器中,您可以使用异步节流器。

TanStack Pacer 中的异步节流

TanStack Pacer 通过 AsyncThrottler 类和 asyncThrottle 函数提供异步节流功能。

基本用法示例

以下是一个演示如何为搜索操作使用异步节流器的基本示例

ts
const throttledSearch = asyncThrottle(
  async (searchTerm: string) => {
    const results = await fetchSearchResults(searchTerm)
    return results
  },
  {
    wait: 500,
    onSuccess: (results, args, throttler) => {
      console.log('Search succeeded:', results)
      console.log('Search arguments:', args)
    },
    onError: (error, args, throttler) => {
      console.error('Search failed:', error)
      console.log('Failed arguments:', args)
    }
  }
)

// Usage
try {
  const results = await throttledSearch('query')
  // Handle successful results
} catch (error) {
  // Handle errors if no onError handler was provided
  console.error('Search failed:', error)
}
const throttledSearch = asyncThrottle(
  async (searchTerm: string) => {
    const results = await fetchSearchResults(searchTerm)
    return results
  },
  {
    wait: 500,
    onSuccess: (results, args, throttler) => {
      console.log('Search succeeded:', results)
      console.log('Search arguments:', args)
    },
    onError: (error, args, throttler) => {
      console.error('Search failed:', error)
      console.log('Failed arguments:', args)
    }
  }
)

// Usage
try {
  const results = await throttledSearch('query')
  // Handle successful results
} catch (error) {
  // Handle errors if no onError handler was provided
  console.error('Search failed:', error)
}

注意: 在使用 React 时,为了更好地与 React 的生命周期集成并自动清理,请优先使用 useAsyncThrottledCallback hook 而非 asyncThrottle 函数。

与同步节流的关键区别

1. 返回值处理

与返回 void 的同步节流器不同,异步版本允许您捕获并使用节流函数的返回值。maybeExecute 方法返回一个 Promise,该 Promise 解析为函数的返回值,允许您等待结果并进行适当处理。

2. 错误处理

异步节流器提供强大的错误处理能力

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

3. 不同的回调函数

AsyncThrottler 支持以下回调:

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

示例

ts
const asyncThrottler = new AsyncThrottler(async (value) => {
  await saveToAPI(value)
}, {
  wait: 500,
  onSuccess: (result, args, throttler) => {
    // Called after each successful execution
    console.log('Async function executed', throttler.store.state.successCount)
    console.log('Executed arguments:', args)
  },
  onSettled: (args, throttler) => {
    // Called after each execution attempt
    console.log('Async function settled', throttler.store.state.settleCount)
    console.log('Settled arguments:', args)
  },
  onError: (error, args, throttler) => {
    // Called if the async function throws an error
    console.error('Async function failed:', error)
    console.log('Failed arguments:', args)
  }
})
const asyncThrottler = new AsyncThrottler(async (value) => {
  await saveToAPI(value)
}, {
  wait: 500,
  onSuccess: (result, args, throttler) => {
    // Called after each successful execution
    console.log('Async function executed', throttler.store.state.successCount)
    console.log('Executed arguments:', args)
  },
  onSettled: (args, throttler) => {
    // Called after each execution attempt
    console.log('Async function settled', throttler.store.state.settleCount)
    console.log('Settled arguments:', args)
  },
  onError: (error, args, throttler) => {
    // Called if the async function throws an error
    console.error('Async function failed:', error)
    console.log('Failed arguments:', args)
  }
})

4. 顺序执行

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

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

动态选项和启用/禁用

与同步节流器一样,异步节流器支持对 waitenabled 进行动态选项设置,这些选项可以是以节流器实例为参数的函数。这使得实现复杂、运行时自适应的节流行为成为可能。

刷新待定执行

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

ts
const asyncThrottler = new AsyncThrottler(asyncFn, { wait: 1000 })

asyncThrottler.maybeExecute('some-arg')
console.log(asyncThrottler.store.state.isPending) // true

// Flush immediately instead of waiting
asyncThrottler.flush()
console.log(asyncThrottler.store.state.isPending) // false
const asyncThrottler = new AsyncThrottler(asyncFn, { wait: 1000 })

asyncThrottler.maybeExecute('some-arg')
console.log(asyncThrottler.store.state.isPending) // true

// Flush immediately instead of waiting
asyncThrottler.flush()
console.log(asyncThrottler.store.state.isPending) // false

状态管理

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

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

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

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

ts
// Default behavior - no reactive state subscriptions
const asyncThrottler = useAsyncThrottler(asyncFn, { wait: 500 })
console.log(asyncThrottler.state) // {}

// Opt-in to re-render when isExecuting changes
const asyncThrottler = useAsyncThrottler(
  asyncFn, 
  { wait: 500 },
  (state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncThrottler.state.isExecuting) // Reactive value

// Multiple state properties
const asyncThrottler = useAsyncThrottler(
  asyncFn,
  { wait: 500 },
  (state) => ({
    isExecuting: state.isExecuting,
    successCount: state.successCount,
    errorCount: state.errorCount
  })
)
// Default behavior - no reactive state subscriptions
const asyncThrottler = useAsyncThrottler(asyncFn, { wait: 500 })
console.log(asyncThrottler.state) // {}

// Opt-in to re-render when isExecuting changes
const asyncThrottler = useAsyncThrottler(
  asyncFn, 
  { wait: 500 },
  (state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncThrottler.state.isExecuting) // Reactive value

// Multiple state properties
const asyncThrottler = useAsyncThrottler(
  asyncFn,
  { wait: 500 },
  (state) => ({
    isExecuting: state.isExecuting,
    successCount: state.successCount,
    errorCount: state.errorCount
  })
)

初始状态

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

ts
// Load initial state from localStorage
const savedState = localStorage.getItem('async-throttler-state')
const initialState = savedState ? JSON.parse(savedState) : {}

const asyncThrottler = new AsyncThrottler(asyncFn, {
  wait: 500,
  initialState
})
// Load initial state from localStorage
const savedState = localStorage.getItem('async-throttler-state')
const initialState = savedState ? JSON.parse(savedState) : {}

const asyncThrottler = new AsyncThrottler(asyncFn, {
  wait: 500,
  initialState
})

订阅状态更改

Store 是响应式的并支持订阅

ts
const asyncThrottler = new AsyncThrottler(asyncFn, { wait: 500 })

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

// Unsubscribe when done
unsubscribe()
const asyncThrottler = new AsyncThrottler(asyncFn, { wait: 500 })

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

// Unsubscribe when done
unsubscribe()

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

可用状态属性

AsyncThrottlerState 包括:

  • errorCount:导致错误的函数执行次数。
  • isExecuting:节流函数当前是否正在异步执行。
  • isPending:节流器是否正在等待超时触发执行
  • lastArgs: 最近一次调用 maybeExecute 时的参数
  • lastExecutionTime:函数最后执行时间的戳(毫秒)
  • lastResult:最近一次成功函数执行的结果。
  • maybeExecuteCount: 调用 maybeExecute 的次数
  • nextExecutionTime:下次可以执行的时间戳(毫秒)
  • settleCount:已完成执行的函数数量(成功或失败)。
  • status:当前执行状态('disabled' | 'idle' | 'pending' | 'executing' | 'settled')。
  • successCount:成功完成的函数执行次数。

框架适配器

每个框架适配器都提供了基于核心异步节流功能构建的 hook,用于与框架的状态管理系统集成。每个框架都可以使用 createAsyncThrottleruseAsyncThrottledCallback 或类似的 hook。


有关核心节流概念和同步节流,请参阅节流指南

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

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

Bytes

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

订阅 Bytes

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

Bytes

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