来自防抖指南的所有核心概念同样适用于异步防抖。
通常,您可以使用普通的同步防抖器,它也能与异步函数一起工作。但对于高级用例,例如想要使用防抖函数的返回值(而不仅仅是调用 setState 副作用),或者将错误处理逻辑放在防抖器中,您可以使用异步防抖器。
TanStack Pacer 通过 AsyncDebouncer 类和 asyncDebounce 函数提供异步防抖。
这是一个展示如何为搜索操作使用异步防抖器的基本示例
const debouncedSearch = asyncDebounce(
async (searchTerm: string) => {
const results = await fetchSearchResults(searchTerm)
return results
},
{
wait: 500,
onSuccess: (results, args, debouncer) => {
console.log('Search succeeded:', results)
console.log('Search arguments:', args)
},
onError: (error, args, debouncer) => {
console.error('Search failed:', error)
console.log('Failed arguments:', args)
}
}
)
// Usage
try {
const results = await debouncedSearch('query')
// Handle successful results
} catch (error) {
// Handle errors if no onError handler was provided
console.error('Search failed:', error)
}
const debouncedSearch = asyncDebounce(
async (searchTerm: string) => {
const results = await fetchSearchResults(searchTerm)
return results
},
{
wait: 500,
onSuccess: (results, args, debouncer) => {
console.log('Search succeeded:', results)
console.log('Search arguments:', args)
},
onError: (error, args, debouncer) => {
console.error('Search failed:', error)
console.log('Failed arguments:', args)
}
}
)
// Usage
try {
const results = await debouncedSearch('query')
// Handle successful results
} catch (error) {
// Handle errors if no onError handler was provided
console.error('Search failed:', error)
}
注意: 在使用 React 时,优先使用 useAsyncDebouncedCallback hook,而不是 asyncDebounce 函数,以更好地与 React 的生命周期和自动清理集成。
与返回 void 的同步防抖器不同,异步版本允许您捕获并使用防抖函数的返回值。maybeExecute 方法返回一个 Promise,该 Promise 会解析为函数返回值,允许您等待结果并进行适当的处理。
异步防抖器提供了强大的错误处理能力。
AsyncDebouncer 支持以下回调:
示例
const asyncDebouncer = new AsyncDebouncer(async (value) => {
await saveToAPI(value)
}, {
wait: 500,
onSuccess: (result, args, debouncer) => {
// Called after each successful execution
console.log('Async function executed', debouncer.store.state.successCount)
console.log('Executed arguments:', args)
},
onSettled: (args, debouncer) => {
// Called after each execution attempt
console.log('Async function settled', debouncer.store.state.settleCount)
console.log('Settled arguments:', args)
},
onError: (error) => {
// Called if the async function throws an error
console.error('Async function failed:', error)
}
})
const asyncDebouncer = new AsyncDebouncer(async (value) => {
await saveToAPI(value)
}, {
wait: 500,
onSuccess: (result, args, debouncer) => {
// Called after each successful execution
console.log('Async function executed', debouncer.store.state.successCount)
console.log('Executed arguments:', args)
},
onSettled: (args, debouncer) => {
// Called after each execution attempt
console.log('Async function settled', debouncer.store.state.settleCount)
console.log('Settled arguments:', args)
},
onError: (error) => {
// Called if the async function throws an error
console.error('Async function failed:', error)
}
})
由于防抖器的 maybeExecute 方法返回一个 Promise,您可以选择在开始下一次执行之前等待每次执行。这使您可以控制执行顺序,并确保每次调用都处理最新的数据。当处理依赖于先前调用结果的操作或在数据一致性至关重要时,这尤其有用。
例如,如果您正在更新用户配置文件,然后立即获取其更新后的数据,您可以在开始获取之前等待更新操作。
与同步防抖器一样,异步防抖器支持 wait 和 enabled 的动态选项,这些选项可以是接收防抖器实例的函数。这允许进行复杂的、运行时自适应的防抖行为。
异步防抖器支持刷新待处理的执行以立即触发它们。
const asyncDebouncer = new AsyncDebouncer(asyncFn, { wait: 1000 })
asyncDebouncer.maybeExecute('some-arg')
console.log(asyncDebouncer.store.state.isPending) // true
// Flush immediately instead of waiting
asyncDebouncer.flush()
console.log(asyncDebouncer.store.state.isPending) // false
const asyncDebouncer = new AsyncDebouncer(asyncFn, { wait: 1000 })
asyncDebouncer.maybeExecute('some-arg')
console.log(asyncDebouncer.store.state.isPending) // true
// Flush immediately instead of waiting
asyncDebouncer.flush()
console.log(asyncDebouncer.store.state.isPending) // false
AsyncDebouncer 类使用 TanStack Store 进行响应式状态管理,提供对执行状态、错误跟踪和执行统计的实时访问。所有状态都存储在 TanStack Store 中,可以通过 asyncDebouncer.store.state 访问。但是,如果您使用的是 React 或 Solid 等框架适配器,则不应从此读取状态。相反,您将从 asyncDebouncer.state 读取状态,并向 useAsyncDebouncer hook 提供一个选择器回调作为第三个参数以选择加入状态跟踪,如下所示。
框架适配器支持一个 selector 参数,该参数允许您指定哪些状态更改将触发重新渲染。这可以通过防止不相关的状态更改导致不必要的重新渲染来优化性能。
默认情况下,debouncer.state 为空(默认选择器为空,为{})。 这是 TanStack Store 的响应式状态 useStore 存储的地方。您必须通过提供一个选择器函数来选择加入状态跟踪。
// Default behavior - no reactive state subscriptions
const asyncDebouncer = useAsyncDebouncer(asyncFn, { wait: 500 })
console.log(asyncDebouncer.state) // {}
// Opt-in to re-render when isExecuting changes
const asyncDebouncer = useAsyncDebouncer(
asyncFn,
{ wait: 500 },
(state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncDebouncer.state.isExecuting) // Reactive value
// Multiple state properties
const asyncDebouncer = useAsyncDebouncer(
asyncFn,
{ wait: 500 },
(state) => ({
isExecuting: state.isExecuting,
successCount: state.successCount,
errorCount: state.errorCount
})
)
// Default behavior - no reactive state subscriptions
const asyncDebouncer = useAsyncDebouncer(asyncFn, { wait: 500 })
console.log(asyncDebouncer.state) // {}
// Opt-in to re-render when isExecuting changes
const asyncDebouncer = useAsyncDebouncer(
asyncFn,
{ wait: 500 },
(state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncDebouncer.state.isExecuting) // Reactive value
// Multiple state properties
const asyncDebouncer = useAsyncDebouncer(
asyncFn,
{ wait: 500 },
(state) => ({
isExecuting: state.isExecuting,
successCount: state.successCount,
errorCount: state.errorCount
})
)
在创建异步防抖器时,您可以提供初始状态值。这通常用于从持久存储中恢复状态。
// Load initial state from localStorage
const savedState = localStorage.getItem('async-debouncer-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const asyncDebouncer = new AsyncDebouncer(asyncFn, {
wait: 500,
initialState
})
// Load initial state from localStorage
const savedState = localStorage.getItem('async-debouncer-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const asyncDebouncer = new AsyncDebouncer(asyncFn, {
wait: 500,
initialState
})
Store 是响应式的,并支持订阅。
const asyncDebouncer = new AsyncDebouncer(asyncFn, { wait: 500 })
// Subscribe to state changes
const unsubscribe = asyncDebouncer.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
const asyncDebouncer = new AsyncDebouncer(asyncFn, { wait: 500 })
// Subscribe to state changes
const unsubscribe = asyncDebouncer.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
注意: 当使用框架适配器时,这是不必要的,因为底层的 useStore hook 已经完成了此操作。您也可以根据需要导入并使用 TanStack Store 中的 useStore 来将 debouncer.store.state 转换为具有自定义选择器的响应式状态。
AsyncDebouncerState 包括:
每个框架适配器都提供基于核心异步防抖功能的 hooks,以与框架的状态管理系统集成。例如 createAsyncDebouncer、useAsyncDebouncedCallback 或类似的 hooks 适用于每个框架。
有关核心防抖概念和同步防抖,请参阅防抖指南。
您的每周 JavaScript 资讯。每周一免费发送给超过 10 万开发者。