
Tanstack Pacer
- 83 installs
- 14 repo stars
- Updated March 2, 2026
- oakoss/agent-skills
Helps with ai & agent building tasks during AI-assisted development.
About
tanstack-pacer is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- tanstack-pacer
- AI & Agent Building
- AI-coding skill
Tanstack Pacer by the numbers
- 83 all-time installs (skills.sh)
- +2 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #5,144 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/oakoss/agent-skills --skill tanstack-pacerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 83 |
|---|---|
| repo stars | ★ 14 |
| Last updated | March 2, 2026 |
| Repository | oakoss/agent-skills ↗ |
What it does
Helps with ai & agent building tasks during AI-assisted development.
Files
TanStack Pacer
Overview
TanStack Pacer is a lightweight, type-safe library for controlling function execution timing through debouncing, throttling, rate limiting, queuing, and batching. It provides framework-agnostic core classes with dedicated React hooks at multiple abstraction levels (instance, callback, state, value).
When to use: Debouncing search input, throttling scroll/resize handlers, enforcing API rate limits, queuing async tasks with concurrency control, batching multiple operations into single requests.
When NOT to use: Simple one-off delays (use setTimeout), server-side rate limiting at the infrastructure level (use middleware/API gateway), complex job scheduling (use a task queue like BullMQ).
Quick Reference
| Pattern | API | Key Points |
|---|---|---|
| Debounce function | Debouncer / debounce(fn, opts) | Waits for inactivity; no maxWait option by design |
| Throttle function | Throttler / throttle(fn, opts) | Even spacing; leading and trailing both default true |
| Rate limit | RateLimiter / rateLimit(fn, opts) | Fixed or sliding window; rejects calls over limit |
| Queue items | Queuer / queue(fn, opts) | FIFO default; supports LIFO, priority, expiration |
| Async queue | AsyncQueuer / asyncQueue(fn, opts) | Concurrency control, retry, error callbacks |
| Async batch | AsyncBatcher / asyncBatch(fn, opts) | Collects items, processes as batch after wait/maxSize |
| React debounce | useDebouncer / useDebouncedCallback | Instance hook vs simple callback hook |
| React throttle | useThrottler / useThrottledCallback | Instance hook vs simple callback hook |
| React rate limit | useRateLimiter / useRateLimitedCallback | Instance hook vs simple callback hook |
| React queue | useQueuer / useQueuedState | Instance hook vs state-integrated hook |
| React async queue | useAsyncQueuer / useAsyncQueuedState | Concurrency + state management |
| React batch | useBatcher / useAsyncBatcher | Sync and async batching hooks |
| State hooks | useDebouncedState, useThrottledState | Integrate with React state directly |
| Value hooks | useDebouncedValue, useThrottledValue | Create derived debounced/throttled values |
Common Mistakes
| Mistake | Correct Pattern |
|---|---|
Using maxWait on Debouncer | Debouncer has no maxWait; use Throttler for evenly spaced execution |
| Creating instances inside render | Create with hooks (useDebouncer, useThrottler) to manage lifecycle |
Ignoring maybeExecute return | Rate limiter and throttler may reject calls; check state or use callbacks |
| Using debounce when throttle is needed | Debounce waits for pause; throttle guarantees max-once-per-interval |
| Not cleaning up on unmount | React hooks handle cleanup automatically; manual instances need cancel() |
| Using Queuer when items can be dropped | Queuers process every item; use throttle/debounce if dropping is acceptable |
| Fixed window when sliding is needed | Fixed windows allow bursts at boundaries; sliding window gives smoother rate |
Forgetting onReject on RateLimiter | Rejected calls are silent by default; add onReject for user feedback |
Not passing enabled: false to disable | All utilities support enabled option to temporarily disable processing |
Delegation
If the tanstack-query skill is available, delegate data fetching and cache management tasks to it. TanStack Pacer complements Query for controlling request frequency.Otherwise, recommend: npx skills add oakoss/agent-skills --skill tanstack-query- Execution timing patterns: Use this skill
- Data fetching and caching: Delegate to
tanstack-query - Component architecture: Delegate to framework-specific skills
References
- Throttle and debounce patterns
- Rate limiting patterns
- Queuing and async queuing
- React hooks and integration
Queuing and Async Queuing
Overview
Unlike debouncing, throttling, and rate limiting which drop or delay executions, queuers ensure every item is processed. They manage the flow of operations without losing requests, making them ideal for scenarios where data loss is unacceptable.
Queuer Class (Synchronous)
import { Queuer } from '@tanstack/pacer';
const queuer = new Queuer((item: string) => processItem(item), {
wait: 100,
maxSize: 50,
started: true,
});
queuer.addItem('task-1');
queuer.addItem('task-2');Queuer Options
| Option | Type | Default | Description |
|---|---|---|---|
wait | number | 0 | Delay between processing items |
maxSize | number | Infinity | Maximum queue size |
started | boolean | true | Whether to start processing immediately |
enabled | boolean | true | Whether the queuer accepts items |
getPriority | (item) => number | — | Priority function (higher = first) |
expirationDuration | number | — | Max time items can stay in queue |
getIsExpired | (item) => boolean | — | Custom expiration check |
onReject | (item, queuer) => void | — | Called when item is rejected (queue full) |
onExpire | (item, queuer) => void | — | Called when item expires |
Queue Ordering
FIFO (Default)
First in, first out. Items are processed in the order they were added:
const queuer = new Queuer(processItem, { wait: 100 });
queuer.addItem('first');
queuer.addItem('second');
queuer.addItem('third');LIFO (Stack)
Last in, first out. Add to back, process from back:
queuer.addItem('item', 'back');
queuer.getNextItem('back');Priority Queue
Provide a getPriority function; higher values are processed first:
import { Queuer } from '@tanstack/pacer';
type Task = { name: string; urgency: number };
const queuer = new Queuer<Task>((task) => processTask(task), {
wait: 100,
getPriority: (task) => task.urgency,
});
queuer.addItem({ name: 'low', urgency: 1 });
queuer.addItem({ name: 'critical', urgency: 10 });
queuer.addItem({ name: 'medium', urgency: 5 });Queue Control
queuer.start();
queuer.stop();
queuer.peek();
queuer.getNextItem();
queuer.getAllItems();
queuer.clear();
queuer.store.state.size;
queuer.store.state.isEmpty;
queuer.store.state.isRunning;queue Function
The functional API for simpler use cases:
import { queue } from '@tanstack/pacer';
const processQueue = queue((item: string) => console.log('Processing:', item), {
wait: 200,
maxSize: 100,
});
processQueue('item-1');
processQueue('item-2');AsyncQueuer Class
The AsyncQueuer extends queuing with concurrency control, async error handling, and retry support. It implements a task pool / worker pool pattern:
import { AsyncQueuer } from '@tanstack/pacer';
const asyncQueuer = new AsyncQueuer<string>(
async (item) => {
const response = await fetch(`/api/process/${item}`);
return response.json();
},
{
concurrency: 3,
wait: 100,
maxSize: 100,
started: true,
onSuccess: (result, item, asyncQueuer) => {
console.log('Processed:', result);
},
onError: (error, item, asyncQueuer) => {
console.error('Failed:', error);
},
},
);
asyncQueuer.addItem('task-1');
asyncQueuer.addItem('task-2');AsyncQueuer Options
Includes all Queuer options plus:
| Option | Type | Default | Description |
|---|---|---|---|
concurrency | number | 1 | Max concurrent async operations |
onSuccess | (result, item, queuer) => void | — | Called per successful item |
onError | (error, item, queuer) => void | — | Called per failed item |
Concurrency Control
Process multiple items simultaneously while limiting how many run at once:
const uploader = new AsyncQueuer<File>(
async (file) => {
const formData = new FormData();
formData.append('file', file);
await fetch('/api/upload', { method: 'POST', body: formData });
},
{
concurrency: 3,
onSuccess: (_result, file) => {
console.log(`Uploaded: ${file.name}`);
},
},
);
files.forEach((file) => uploader.addItem(file));AsyncQueuer State
asyncQueuer.store.state.activeCount;
asyncQueuer.store.state.pendingCount;
asyncQueuer.store.state.successCount;
asyncQueuer.store.state.errorCount;
asyncQueuer.store.state.isExecuting;
asyncQueuer.store.state.isRunning;
asyncQueuer.store.state.isEmpty;asyncQueue Function
import { asyncQueue } from '@tanstack/pacer';
const processAsync = asyncQueue(
async (item: string) => {
await processItem(item);
},
{ concurrency: 2, wait: 100 },
);
processAsync('item-1');Item Expiration
Remove stale items automatically:
const queuer = new Queuer(processItem, {
expirationDuration: 30_000,
onExpire: (item) => {
console.log('Expired:', item);
},
});Queue Size Limits
Reject items when the queue is full:
const queuer = new Queuer(processItem, {
maxSize: 100,
onReject: (item) => {
console.warn('Queue full, rejected:', item);
},
});Rate Limiting
Overview
Rate limiting restricts how many times a function can execute within a time window. Unlike throttling (even spacing) or debouncing (waiting for inactivity), rate limiting allows bursts up to the limit then blocks until the window resets.
RateLimiter Class
import { RateLimiter } from '@tanstack/pacer';
const limiter = new RateLimiter((id: string) => fetchUserData(id), {
limit: 5,
window: 60_000,
onExecute: (rateLimiter) => {
console.log('Executed:', rateLimiter.store.state.executionCount);
},
onReject: (rateLimiter) => {
console.log(
`Rate limit exceeded. Retry in ${rateLimiter.getMsUntilNextWindow()}ms`,
);
},
});
limiter.maybeExecute('user-1');RateLimiter Options
| Option | Type | Default | Description |
|---|---|---|---|
limit | number | required | Maximum executions per window |
window | number | required | Window duration in milliseconds |
windowType | `'fixed' \ | 'sliding'` | 'fixed' |
enabled | boolean | true | Whether the limiter accepts calls |
onExecute | (limiter) => void | — | Called after successful execution |
onReject | (limiter) => void | — | Called when execution is rejected |
Window Types
Fixed Window
All executions within the window count toward the limit. The window resets completely after the period:
Window 1 (0-60s): [X X X X X] [blocked] [blocked]
Window 2 (60-120s): [X X X X X] [blocked]Allows bursts at window boundaries (up to 2 * limit calls in a short period spanning two windows).
const limiter = new RateLimiter(handler, {
limit: 10,
window: 60_000,
windowType: 'fixed',
});Sliding Window
A rolling window that allows executions as old ones expire, providing a smoother rate:
Time: 0s 10s 20s 30s 40s 50s 60s 70s
Calls: X X X X X - X X
^ first call expired, slot opensconst limiter = new RateLimiter(handler, {
limit: 5,
window: 60_000,
windowType: 'sliding',
});Use sliding windows when you need consistent rate enforcement without boundary bursts.
RateLimiter State and Methods
limiter.getRemainingInWindow();
limiter.getMsUntilNextWindow();
limiter.store.state.executionCount;
limiter.store.state.rejectionCount;
limiter.setOptions({ limit: 10 });
limiter.reset();rateLimit Function
The functional API for simpler use cases:
import { rateLimit } from '@tanstack/pacer';
const rateLimitedFetch = rateLimit((url: string) => fetch(url), {
limit: 10,
window: 60_000,
});
rateLimitedFetch('/api/data');Async Rate Limiting
For async operations with success/error handling:
import { AsyncRateLimiter } from '@tanstack/pacer';
const asyncLimiter = new AsyncRateLimiter(
async (id: string) => {
const response = await fetch(`/api/users/${id}`);
return response.json();
},
{
limit: 5,
window: 60_000,
onSuccess: (result, limiter) => {
console.log('Fetched:', result);
},
onError: (error, limiter) => {
console.error('Failed:', error);
},
onReject: (limiter) => {
console.warn('Rate limited');
},
},
);
await asyncLimiter.maybeExecute('user-123');Choosing: Rate Limit vs Throttle vs Debounce
| Technique | Behavior | Best For |
|---|---|---|
| Rate limit | Allows bursts up to limit, then blocks | API call quotas, external service limits |
| Throttle | Even spacing between executions | Scroll handlers, UI updates |
| Debounce | Waits for inactivity to stop | Search input, form validation |
Input: --X-X-XX---X-X-X-XX-X---
Rate limit --X-X-XX---------XX-X--- (limit: 5, blocks after 5)
(limit=5):
Throttle --X---X----X---X----X--- (evenly spaced)
(200ms):
Debounce ----------X---------X--- (after inactivity)
(200ms):Handling Rejections
Always provide user feedback when calls are rejected:
const limiter = new RateLimiter(submitForm, {
limit: 3,
window: 60_000,
onReject: (limiter) => {
const waitMs = limiter.getMsUntilNextWindow();
showToast(`Too many attempts. Try again in ${Math.ceil(waitMs / 1000)}s`);
},
});React Hooks and Integration
Installation
npm install @tanstack/react-pacerThe React package re-exports everything from @tanstack/pacer, so no separate core install is needed.
Hook Abstraction Levels
TanStack Pacer React hooks come in four abstraction levels for each utility:
| Level | Pattern | Example | Use Case |
|---|---|---|---|
| Instance | useDebouncer | Full class access | Complex control flow, cancel/flush |
| Callback | useDebouncedCallback | Stable debounced function | Event handlers, simple callbacks |
| State | useDebouncedState | Debounced React state | Form inputs, controlled components |
| Value | useDebouncedValue | Derived debounced value | Derived/computed values |
Debouncer Hooks
useDebouncer
Full access to the Debouncer instance:
import { useDebouncer } from '@tanstack/react-pacer';
function SearchComponent() {
const debouncer = useDebouncer((query: string) => fetchSearchResults(query), {
wait: 500,
});
return (
<input
onChange={(e) => debouncer.maybeExecute(e.target.value)}
placeholder="Search..."
/>
);
}useDebouncer with State Selector
Opt in to re-renders for specific state changes:
const debouncer = useDebouncer(
(query: string) => fetchSearchResults(query),
{ wait: 500 },
(state) => ({ isPending: state.isPending }),
);
const { isPending } = debouncer.state;useDebouncedCallback
Returns a stable debounced function reference:
import { useDebouncedCallback } from '@tanstack/react-pacer';
function SearchInput() {
const handleSearch = useDebouncedCallback(
(query: string) => fetchSearchResults(query),
{ wait: 500 },
);
return <input type="search" onChange={(e) => handleSearch(e.target.value)} />;
}useDebouncedState
Manages debounced React state directly:
import { useDebouncedState } from '@tanstack/react-pacer';
function FilterForm() {
const [filter, setFilter] = useDebouncedState('', { wait: 300 });
return (
<div>
<input onChange={(e) => setFilter(e.target.value)} />
<p>Debounced filter: {filter}</p>
</div>
);
}useDebouncedValue
Creates a debounced version of a value:
import { useDebouncedValue } from '@tanstack/react-pacer';
function SearchResults({ query }: { query: string }) {
const debouncedQuery = useDebouncedValue(query, { wait: 300 });
return <Results query={debouncedQuery} />;
}Throttler Hooks
useThrottler
import { useThrottler } from '@tanstack/react-pacer';
function ScrollTracker() {
const throttler = useThrottler(
(position: number) => updateScrollPosition(position),
{ wait: 200, leading: true, trailing: true },
);
useEffect(() => {
const handler = () => throttler.maybeExecute(window.scrollY);
window.addEventListener('scroll', handler);
return () => window.removeEventListener('scroll', handler);
}, [throttler]);
return null;
}useThrottledCallback
import { useThrottledCallback } from '@tanstack/react-pacer';
function LivePreview() {
const handleUpdate = useThrottledCallback(
(content: string) => renderPreview(content),
{ wait: 200 },
);
return <textarea onChange={(e) => handleUpdate(e.target.value)} />;
}useThrottledValue
import { useThrottledValue } from '@tanstack/react-pacer';
function MouseTracker({ position }: { position: { x: number; y: number } }) {
const throttledPosition = useThrottledValue(position, { wait: 100 });
return (
<div>
Position: {throttledPosition.x}, {throttledPosition.y}
</div>
);
}Rate Limiter Hooks
useRateLimiter
import { useRateLimiter } from '@tanstack/react-pacer';
function SubmitButton() {
const limiter = useRateLimiter(
() => submitForm(),
{
limit: 3,
window: 60_000,
onReject: () => showToast('Too many attempts'),
},
(state) => ({ executionCount: state.executionCount }),
);
return (
<button onClick={() => limiter.maybeExecute()}>
Submit ({limiter.state.executionCount}/3)
</button>
);
}useRateLimitedCallback
import { useRateLimitedCallback } from '@tanstack/react-pacer';
function LikeButton() {
const handleLike = useRateLimitedCallback(
(postId: string) => likePost(postId),
{ limit: 5, window: 10_000 },
);
return <button onClick={() => handleLike(postId)}>Like</button>;
}Queuer Hooks
useQueuer
import { useQueuer } from '@tanstack/react-pacer';
function NotificationQueue() {
const queuer = useQueuer<string>(
(message) => showNotification(message),
{ wait: 2000 },
(state) => ({ size: state.size }),
);
return (
<div>
<button onClick={() => queuer.addItem('New notification')}>
Add ({queuer.state.size} pending)
</button>
</div>
);
}useQueuedState
Combines queue with React state management. Takes a processing function, queue options, and an optional selector. Returns a tuple of [items, addItem, queuerInstance]:
import { useQueuedState } from '@tanstack/react-pacer';
function TaskProcessor() {
const [tasks, addTask] = useQueuedState<string>(
(task) => console.log('Processing:', task),
{ wait: 500 },
);
return (
<div>
<button onClick={() => addTask('new-task')}>Add Task</button>
<ul>
{tasks.map((task, i) => (
<li key={i}>{task}</li>
))}
</ul>
</div>
);
}Async Queuer Hooks
useAsyncQueuer
import { useAsyncQueuer } from '@tanstack/react-pacer';
function FileUploader() {
const uploader = useAsyncQueuer<File>(
async (file) => {
const formData = new FormData();
formData.append('file', file);
await fetch('/api/upload', { method: 'POST', body: formData });
},
{
concurrency: 3,
onSuccess: (_result, file) => console.log(`Uploaded: ${file.name}`),
onError: (error) => console.error('Upload failed:', error),
},
(state) => ({
activeCount: state.activeCount,
pendingCount: state.pendingCount,
}),
);
return (
<div>
<input
type="file"
multiple
onChange={(e) => {
Array.from(e.target.files ?? []).forEach((f) => uploader.addItem(f));
}}
/>
<p>
Active: {uploader.state.activeCount}, Pending:{' '}
{uploader.state.pendingCount}
</p>
</div>
);
}Async Callback Hooks
useAsyncDebouncedCallback
Returns a stable debounced function for async operations. Simpler than useAsyncDebouncer but does not expose the underlying instance for manual cancellation or state access:
import { useAsyncDebouncedCallback } from '@tanstack/react-pacer';
function EmailValidator() {
const [result, setResult] = useState<string | null>(null);
const validateEmail = useAsyncDebouncedCallback(
async (email: string) => {
const res = await fetch(`/api/validate-email?email=${email}`);
const data = await res.json();
setResult(data.isValid ? 'Valid' : 'Invalid');
},
{ wait: 750 },
);
return <input type="email" onChange={(e) => validateEmail(e.target.value)} />;
}useAsyncThrottledCallback
Returns a stable throttled function for async operations:
import { useAsyncThrottledCallback } from '@tanstack/react-pacer';
function AutoSave({ content }: { content: string }) {
const saveContent = useAsyncThrottledCallback(
async (text: string) => {
await fetch('/api/save', {
method: 'POST',
body: JSON.stringify({ content: text }),
});
},
{ wait: 5000 },
);
useEffect(() => {
saveContent(content);
}, [content, saveContent]);
return null;
}Async Variants
All instance-level hooks have async counterparts:
| Sync Hook | Async Hook |
|---|---|
useDebouncer | useAsyncDebouncer |
useThrottler | useAsyncThrottler |
useRateLimiter | useAsyncRateLimiter |
useQueuer | useAsyncQueuer |
useBatcher | useAsyncBatcher |
Async hooks add onSuccess and onError callbacks and return Promises from maybeExecute.
Callback-level async hooks:
| Sync Hook | Async Hook |
|---|---|
useDebouncedCallback | useAsyncDebouncedCallback |
useThrottledCallback | useAsyncThrottledCallback |
useRateLimitedCallback | useAsyncRateLimitedCallback |
Selector Pattern
All instance hooks accept an optional third argument: a selector function that controls which state changes trigger re-renders:
const debouncer = useDebouncer(fn, { wait: 500 }, (state) => ({
isPending: state.isPending,
executionCount: state.executionCount,
canLeadingExecute: state.canLeadingExecute,
}));
debouncer.state.isPending;
debouncer.state.executionCount;
debouncer.state.canLeadingExecute;Without a selector, no reactive state subscriptions are made, and the hook does not trigger re-renders on state changes.
canLeadingExecute
The canLeadingExecute state property is available on debouncer, throttler, and their async variants. It indicates whether the next call to maybeExecute would trigger a leading-edge execution:
const debouncer = useDebouncer(
(query: string) => fetchResults(query),
{ wait: 500 },
(state) => ({ canLeadingExecute: state.canLeadingExecute }),
);
return (
<button
disabled={!debouncer.state.canLeadingExecute}
onClick={() => debouncer.maybeExecute('search')}
>
Search
</button>
);Cleanup
React hooks automatically manage cleanup on unmount. For manual class instances used outside of hooks, call cancel() in cleanup:
useEffect(() => {
const debouncer = new Debouncer(handler, { wait: 300 });
return () => debouncer.cancel();
}, []);Throttle and Debounce
When to Use Which
- Debounce: Collapse rapid calls into one execution after activity stops. Best for search input, form validation, window resize end.
- Throttle: Guarantee evenly spaced executions regardless of call frequency. Best for scroll handlers, live updates, polling-like behavior.
Debouncer Class
import { Debouncer } from '@tanstack/pacer';
const debouncer = new Debouncer((query: string) => fetchSearchResults(query), {
wait: 500,
enabled: true,
});
debouncer.maybeExecute('search term');
debouncer.cancel();
debouncer.flush();Debouncer Options
| Option | Type | Default | Description |
|---|---|---|---|
wait | number | required | Milliseconds to wait after last call |
enabled | boolean | true | Whether the debouncer accepts calls |
onExecute | (debouncer) => void | — | Called after function executes |
Debouncer State
Access state via debouncer.store.state:
debouncer.store.state.isPending;
debouncer.store.state.executionCount;
debouncer.store.state.status;
debouncer.store.state.lastArgs;No maxWait by Design
The Debouncer intentionally omits maxWait. If you need executions to run at regular intervals even during continuous activity, use the Throttler instead.
debounce Function
The functional API creates a Debouncer instance with a simpler interface:
import { debounce } from '@tanstack/pacer';
const debouncedSearch = debounce((query: string) => fetchSearchResults(query), {
wait: 300,
});
debouncedSearch('term');Throttler Class
import { Throttler } from '@tanstack/pacer';
const throttler = new Throttler((value: number) => updatePosition(value), {
wait: 200,
leading: true,
trailing: true,
enabled: true,
});
throttler.maybeExecute(42);
throttler.cancel();
throttler.flush();Throttler Options
| Option | Type | Default | Description |
|---|---|---|---|
wait | number | required | Minimum interval between executions |
leading | boolean | true | Execute immediately on first call |
trailing | boolean | true | Execute after wait period if called during throttle |
enabled | boolean | true | Whether the throttler accepts calls |
onExecute | (throttler) => void | — | Called after function executes |
Leading and Trailing Edge Behavior
Calls: --|--|----|--------|--
leading: X X (immediate on first call)
trailing: X X X (after wait period ends)
both: X X X X X (both edges)
neither: (no executions - not useful)leading: true, trailing: true(default): Executes on both edges, most responsiveleading: true, trailing: false: Only the first call in each window executesleading: false, trailing: true: Only executes after the wait period
Throttler State
Access state via throttler.store.state:
throttler.store.state.isPending;
throttler.store.state.executionCount;
throttler.store.state.status;
throttler.store.state.lastArgs;throttle Function
import { throttle } from '@tanstack/pacer';
const throttledScroll = throttle((position: number) => updateUI(position), {
wait: 100,
leading: true,
trailing: true,
});
window.addEventListener('scroll', () => throttledScroll(window.scrollY));Async Variants
Both utilities have async counterparts that handle Promises:
import { AsyncDebouncer, AsyncThrottler } from '@tanstack/pacer';
const asyncDebouncer = new AsyncDebouncer(
async (query: string) => {
const results = await fetch(`/api/search?q=${query}`);
return results.json();
},
{
wait: 500,
onSuccess: (result, asyncDebouncer) => {
console.log('Search complete:', result);
},
onError: (error, asyncDebouncer) => {
console.error('Search failed:', error);
},
},
);
await asyncDebouncer.maybeExecute('query');Async-Specific Options
| Option | Type | Description |
|---|---|---|
onSuccess | (result, instance) => void | Called on successful execution |
onError | (error, instance) => void | Called on failed execution |
abortPrevious | boolean | Cancel previous pending async call |
Dynamic Option Updates
All classes support runtime option changes:
const throttler = new Throttler(handler, { wait: 200 });
throttler.setOptions({ wait: 500 });Cancel and Flush
Both Debouncer and Throttler support cancel and flush:
debouncer.cancel();
debouncer.flush();cancel(): Cancels any pending execution without running the functionflush(): Immediately executes the pending call (if any) and resets the timer
Reset
Reset all internal state and counters:
throttler.reset();