@tanstack/pacer 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/cjs/async-batcher.cjs +163 -0
  2. package/dist/cjs/async-batcher.cjs.map +1 -0
  3. package/dist/cjs/async-batcher.d.cts +273 -0
  4. package/dist/cjs/async-debouncer.cjs +149 -162
  5. package/dist/cjs/async-debouncer.cjs.map +1 -1
  6. package/dist/cjs/async-debouncer.d.cts +76 -57
  7. package/dist/cjs/async-queuer.cjs +282 -343
  8. package/dist/cjs/async-queuer.cjs.map +1 -1
  9. package/dist/cjs/async-queuer.d.cts +121 -100
  10. package/dist/cjs/async-rate-limiter.cjs +128 -185
  11. package/dist/cjs/async-rate-limiter.cjs.map +1 -1
  12. package/dist/cjs/async-rate-limiter.d.cts +72 -61
  13. package/dist/cjs/async-throttler.cjs +168 -178
  14. package/dist/cjs/async-throttler.cjs.map +1 -1
  15. package/dist/cjs/async-throttler.d.cts +97 -69
  16. package/dist/cjs/batcher.cjs +110 -119
  17. package/dist/cjs/batcher.cjs.map +1 -1
  18. package/dist/cjs/batcher.d.cts +76 -51
  19. package/dist/cjs/debouncer.cjs +97 -85
  20. package/dist/cjs/debouncer.cjs.map +1 -1
  21. package/dist/cjs/debouncer.d.cts +54 -26
  22. package/dist/cjs/index.cjs +3 -6
  23. package/dist/cjs/index.cjs.map +1 -1
  24. package/dist/cjs/index.d.cts +1 -1
  25. package/dist/cjs/queuer.cjs +247 -294
  26. package/dist/cjs/queuer.cjs.map +1 -1
  27. package/dist/cjs/queuer.d.cts +102 -81
  28. package/dist/cjs/rate-limiter.cjs +97 -130
  29. package/dist/cjs/rate-limiter.cjs.map +1 -1
  30. package/dist/cjs/rate-limiter.d.cts +50 -37
  31. package/dist/cjs/throttler.cjs +107 -123
  32. package/dist/cjs/throttler.cjs.map +1 -1
  33. package/dist/cjs/throttler.d.cts +59 -35
  34. package/dist/cjs/utils.cjs +0 -13
  35. package/dist/cjs/utils.cjs.map +1 -1
  36. package/dist/cjs/utils.d.cts +0 -1
  37. package/dist/esm/async-batcher.d.ts +273 -0
  38. package/dist/esm/async-batcher.js +163 -0
  39. package/dist/esm/async-batcher.js.map +1 -0
  40. package/dist/esm/async-debouncer.d.ts +76 -57
  41. package/dist/esm/async-debouncer.js +149 -162
  42. package/dist/esm/async-debouncer.js.map +1 -1
  43. package/dist/esm/async-queuer.d.ts +121 -100
  44. package/dist/esm/async-queuer.js +282 -343
  45. package/dist/esm/async-queuer.js.map +1 -1
  46. package/dist/esm/async-rate-limiter.d.ts +72 -61
  47. package/dist/esm/async-rate-limiter.js +128 -185
  48. package/dist/esm/async-rate-limiter.js.map +1 -1
  49. package/dist/esm/async-throttler.d.ts +97 -69
  50. package/dist/esm/async-throttler.js +168 -178
  51. package/dist/esm/async-throttler.js.map +1 -1
  52. package/dist/esm/batcher.d.ts +76 -51
  53. package/dist/esm/batcher.js +110 -119
  54. package/dist/esm/batcher.js.map +1 -1
  55. package/dist/esm/debouncer.d.ts +54 -26
  56. package/dist/esm/debouncer.js +97 -85
  57. package/dist/esm/debouncer.js.map +1 -1
  58. package/dist/esm/index.d.ts +1 -1
  59. package/dist/esm/index.js +4 -7
  60. package/dist/esm/queuer.d.ts +102 -81
  61. package/dist/esm/queuer.js +247 -294
  62. package/dist/esm/queuer.js.map +1 -1
  63. package/dist/esm/rate-limiter.d.ts +50 -37
  64. package/dist/esm/rate-limiter.js +97 -130
  65. package/dist/esm/rate-limiter.js.map +1 -1
  66. package/dist/esm/throttler.d.ts +59 -35
  67. package/dist/esm/throttler.js +107 -123
  68. package/dist/esm/throttler.js.map +1 -1
  69. package/dist/esm/utils.d.ts +0 -1
  70. package/dist/esm/utils.js +0 -13
  71. package/dist/esm/utils.js.map +1 -1
  72. package/package.json +14 -11
  73. package/src/async-batcher.ts +475 -0
  74. package/src/async-debouncer.ts +201 -121
  75. package/src/async-queuer.ts +337 -216
  76. package/src/async-rate-limiter.ts +176 -136
  77. package/src/async-throttler.ts +233 -139
  78. package/src/batcher.ts +158 -92
  79. package/src/debouncer.ts +135 -52
  80. package/src/index.ts +1 -1
  81. package/src/queuer.ts +349 -226
  82. package/src/rate-limiter.ts +125 -80
  83. package/src/throttler.ts +152 -78
  84. package/src/utils.ts +0 -15
  85. package/dist/cjs/compare.cjs +0 -72
  86. package/dist/cjs/compare.cjs.map +0 -1
  87. package/dist/cjs/compare.d.cts +0 -12
  88. package/dist/esm/compare.d.ts +0 -12
  89. package/dist/esm/compare.js +0 -72
  90. package/dist/esm/compare.js.map +0 -1
  91. package/src/compare.ts +0 -105
@@ -1,6 +1,67 @@
1
+ import { Store } from '@tanstack/store'
1
2
  import { parseFunctionOrValue } from './utils'
2
3
  import type { AnyAsyncFunction, OptionalKeys } from './types'
3
4
 
5
+ export interface AsyncThrottlerState<TFn extends AnyAsyncFunction> {
6
+ /**
7
+ * Number of function executions that have resulted in errors
8
+ */
9
+ errorCount: number
10
+ /**
11
+ * Whether the throttled function is currently executing asynchronously
12
+ */
13
+ isExecuting: boolean
14
+ /**
15
+ * Whether the throttler is waiting for the timeout to trigger execution
16
+ */
17
+ isPending: boolean
18
+ /**
19
+ * The arguments from the most recent call to maybeExecute
20
+ */
21
+ lastArgs: Parameters<TFn> | undefined
22
+ /**
23
+ * Timestamp of the last function execution in milliseconds
24
+ */
25
+ lastExecutionTime: number
26
+ /**
27
+ * The result from the most recent successful function execution
28
+ */
29
+ lastResult: ReturnType<TFn> | undefined
30
+ /**
31
+ * Timestamp when the next execution can occur in milliseconds
32
+ */
33
+ nextExecutionTime: number
34
+ /**
35
+ * Number of function executions that have completed (either successfully or with errors)
36
+ */
37
+ settleCount: number
38
+ /**
39
+ * Current execution status - 'idle' when not active, 'pending' when waiting, 'executing' when running, 'settled' when completed
40
+ */
41
+ status: 'disabled' | 'idle' | 'pending' | 'executing' | 'settled'
42
+ /**
43
+ * Number of function executions that have completed successfully
44
+ */
45
+ successCount: number
46
+ }
47
+
48
+ function getDefaultAsyncThrottlerState<
49
+ TFn extends AnyAsyncFunction,
50
+ >(): AsyncThrottlerState<TFn> {
51
+ return structuredClone({
52
+ errorCount: 0,
53
+ isExecuting: false,
54
+ isPending: false,
55
+ lastArgs: undefined,
56
+ lastExecutionTime: 0,
57
+ lastResult: undefined,
58
+ nextExecutionTime: 0,
59
+ settleCount: 0,
60
+ status: 'idle',
61
+ successCount: 0,
62
+ })
63
+ }
64
+
4
65
  /**
5
66
  * Options for configuring an async throttled function
6
67
  */
@@ -11,6 +72,10 @@ export interface AsyncThrottlerOptions<TFn extends AnyAsyncFunction> {
11
72
  * Defaults to true.
12
73
  */
13
74
  enabled?: boolean | ((throttler: AsyncThrottler<TFn>) => boolean)
75
+ /**
76
+ * Initial state for the async throttler
77
+ */
78
+ initialState?: Partial<AsyncThrottlerState<TFn>>
14
79
  /**
15
80
  * Whether to execute the function immediately when called
16
81
  * Defaults to true
@@ -54,7 +119,7 @@ export interface AsyncThrottlerOptions<TFn extends AnyAsyncFunction> {
54
119
 
55
120
  type AsyncThrottlerOptionsWithOptionalCallbacks = OptionalKeys<
56
121
  AsyncThrottlerOptions<any>,
57
- 'onError' | 'onSettled' | 'onSuccess'
122
+ 'initialState' | 'onError' | 'onSettled' | 'onSuccess'
58
123
  >
59
124
 
60
125
  const defaultOptions: AsyncThrottlerOptionsWithOptionalCallbacks = {
@@ -85,6 +150,16 @@ const defaultOptions: AsyncThrottlerOptionsWithOptionalCallbacks = {
85
150
  * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
86
151
  * - The error state can be checked using the underlying AsyncThrottler instance
87
152
  *
153
+ * State Management:
154
+ * - Uses TanStack Store for reactive state management
155
+ * - Use `initialState` to provide initial state values when creating the async throttler
156
+ * - Use `onSuccess` callback to react to successful function execution and implement custom logic
157
+ * - Use `onError` callback to react to function execution errors and implement custom error handling
158
+ * - Use `onSettled` callback to react to function execution completion (success or error) and implement custom logic
159
+ * - The state includes error count, execution status, last execution time, and success/settle counts
160
+ * - State can be accessed via `asyncThrottler.store.state` when using the class directly
161
+ * - When using framework adapters (React/Solid), state is accessed from `asyncThrottler.state`
162
+ *
88
163
  * @example
89
164
  * ```ts
90
165
  * const throttler = new AsyncThrottler(async (value: string) => {
@@ -103,18 +178,13 @@ const defaultOptions: AsyncThrottlerOptionsWithOptionalCallbacks = {
103
178
  * ```
104
179
  */
105
180
  export class AsyncThrottler<TFn extends AnyAsyncFunction> {
106
- private _options: AsyncThrottlerOptionsWithOptionalCallbacks
107
- private _abortController: AbortController | null = null
108
- private _errorCount = 0
109
- private _isExecuting = false
110
- private _lastArgs: Parameters<TFn> | undefined
111
- private _lastExecutionTime = 0
112
- private _lastResult: ReturnType<TFn> | undefined
113
- private _nextExecutionTime = 0
114
- private _settleCount = 0
115
- private _successCount = 0
116
- private _timeoutId: NodeJS.Timeout | null = null
117
- private _resolvePreviousPromise:
181
+ readonly store: Store<Readonly<AsyncThrottlerState<TFn>>> = new Store<
182
+ AsyncThrottlerState<TFn>
183
+ >(getDefaultAsyncThrottlerState<TFn>())
184
+ options: AsyncThrottlerOptions<TFn>
185
+ #abortController: AbortController | null = null
186
+ #timeoutId: NodeJS.Timeout | null = null
187
+ #resolvePreviousPromise:
118
188
  | ((value?: ReturnType<TFn> | undefined) => void)
119
189
  | null = null
120
190
 
@@ -122,208 +192,222 @@ export class AsyncThrottler<TFn extends AnyAsyncFunction> {
122
192
  private fn: TFn,
123
193
  initialOptions: AsyncThrottlerOptions<TFn>,
124
194
  ) {
125
- this._options = {
195
+ this.options = {
126
196
  ...defaultOptions,
127
197
  ...initialOptions,
128
198
  throwOnError: initialOptions.throwOnError ?? !initialOptions.onError,
129
199
  }
200
+ this.#setState(this.options.initialState ?? {})
130
201
  }
131
202
 
132
203
  /**
133
- * Updates the throttler options
204
+ * Updates the async throttler options
134
205
  */
135
- setOptions(newOptions: Partial<AsyncThrottlerOptions<TFn>>): void {
136
- this._options = { ...this._options, ...newOptions }
206
+ setOptions = (newOptions: Partial<AsyncThrottlerOptions<TFn>>): void => {
207
+ this.options = { ...this.options, ...newOptions }
137
208
 
138
- // End the pending state if the debouncer is disabled
139
- if (!this._options.enabled) {
209
+ // End the pending state if the throttler is disabled
210
+ if (!this.#getEnabled()) {
140
211
  this.cancel()
141
212
  }
142
213
  }
143
214
 
144
- /**
145
- * Returns the current options
146
- */
147
- getOptions(): AsyncThrottlerOptions<TFn> {
148
- return this._options
215
+ #setState = (newState: Partial<AsyncThrottlerState<TFn>>): void => {
216
+ this.store.setState((state) => {
217
+ const combinedState = {
218
+ ...state,
219
+ ...newState,
220
+ }
221
+ const { isPending, isExecuting, settleCount } = combinedState
222
+ return {
223
+ ...combinedState,
224
+ status: !this.#getEnabled()
225
+ ? 'disabled'
226
+ : isPending
227
+ ? 'pending'
228
+ : isExecuting
229
+ ? 'executing'
230
+ : settleCount > 0
231
+ ? 'settled'
232
+ : 'idle',
233
+ }
234
+ })
149
235
  }
150
236
 
151
237
  /**
152
- * Returns the current enabled state of the throttler
238
+ * Returns the current enabled state of the async throttler
153
239
  */
154
- getEnabled(): boolean {
155
- return !!parseFunctionOrValue(this._options.enabled, this)
240
+ #getEnabled = (): boolean => {
241
+ return !!parseFunctionOrValue(this.options.enabled, this)
156
242
  }
157
243
 
158
244
  /**
159
245
  * Returns the current wait time in milliseconds
160
246
  */
161
- getWait(): number {
162
- return parseFunctionOrValue(this._options.wait, this)
247
+ #getWait = (): number => {
248
+ return parseFunctionOrValue(this.options.wait, this)
163
249
  }
164
250
 
165
251
  /**
166
- * Attempts to execute the throttled function.
167
- * If a call is already in progress, it may be blocked or queued depending on the `wait` option.
252
+ * Attempts to execute the throttled function. The execution behavior depends on the throttler options:
253
+ *
254
+ * - If enough time has passed since the last execution (>= wait period):
255
+ * - With leading=true: Executes immediately
256
+ * - With leading=false: Waits for the next trailing execution
257
+ *
258
+ * - If within the wait period:
259
+ * - With trailing=true: Schedules execution for end of wait period
260
+ * - With trailing=false: Drops the execution
168
261
  *
169
- * Error Handling:
170
- * - If the throttled function throws and no `onError` handler is configured,
171
- * the error will be thrown from this method.
172
- * - If an `onError` handler is configured, errors will be caught and passed to the handler,
173
- * and this method will return undefined.
174
- * - The error state can be checked using `getErrorCount()` and `getIsExecuting()`.
262
+ * @example
263
+ * ```ts
264
+ * const throttled = new AsyncThrottler(fn, { wait: 1000 });
175
265
  *
176
- * @returns A promise that resolves with the function's return value, or undefined if an error occurred and was handled by onError
177
- * @throws The error from the throttled function if no onError handler is configured
266
+ * // First call executes immediately
267
+ * await throttled.maybeExecute('a', 'b');
268
+ *
269
+ * // Call during wait period - gets throttled
270
+ * await throttled.maybeExecute('c', 'd');
271
+ * ```
178
272
  */
179
- async maybeExecute(
273
+ maybeExecute = async (
180
274
  ...args: Parameters<TFn>
181
- ): Promise<ReturnType<TFn> | undefined> {
275
+ ): Promise<ReturnType<TFn> | undefined> => {
276
+ if (!this.#getEnabled()) return undefined
182
277
  const now = Date.now()
183
- const timeSinceLastExecution = now - this._lastExecutionTime
184
- const wait = this.getWait()
278
+ const timeSinceLastExecution = now - this.store.state.lastExecutionTime
279
+ const wait = this.#getWait()
280
+ // Store the most recent arguments for potential trailing execution
281
+ this.#setState({ lastArgs: args })
185
282
 
186
- this.resolvePreviousPromise()
283
+ this.#resolvePreviousPromiseInternal()
187
284
 
188
285
  // Handle leading execution
189
- if (this._options.leading && timeSinceLastExecution >= wait) {
190
- await this.execute(...args)
191
- return this._lastResult
286
+ if (this.options.leading && timeSinceLastExecution >= wait) {
287
+ await this.#execute(...args)
288
+ return this.store.state.lastResult
192
289
  } else {
193
- // Store the most recent arguments for potential trailing execution
194
- this._lastArgs = args
195
-
196
290
  return new Promise((resolve) => {
197
- this._resolvePreviousPromise = resolve
291
+ this.#resolvePreviousPromise = resolve
198
292
  // Clear any existing timeout to ensure we use the latest arguments
199
- if (this._timeoutId) {
200
- clearTimeout(this._timeoutId)
201
- }
293
+ this.#clearTimeout()
202
294
 
203
295
  // Set up trailing execution if enabled
204
- if (this._options.trailing) {
205
- const _timeSinceLastExecution = this._lastExecutionTime
206
- ? now - this._lastExecutionTime
296
+ if (this.options.trailing) {
297
+ const _timeSinceLastExecution = this.store.state.lastExecutionTime
298
+ ? now - this.store.state.lastExecutionTime
207
299
  : 0
208
300
  const timeoutDuration = wait - _timeSinceLastExecution
209
- this._timeoutId = setTimeout(async () => {
210
- if (this._lastArgs !== undefined) {
211
- await this.execute(...this._lastArgs)
301
+ this.#setState({ isPending: true })
302
+ this.#timeoutId = setTimeout(async () => {
303
+ if (this.store.state.lastArgs !== undefined) {
304
+ await this.#execute(...this.store.state.lastArgs)
212
305
  }
213
- this._resolvePreviousPromise = null
214
- resolve(this._lastResult)
306
+ this.#resolvePreviousPromise = null
307
+ resolve(this.store.state.lastResult)
215
308
  }, timeoutDuration)
216
309
  }
217
310
  })
218
311
  }
219
312
  }
220
313
 
221
- private async execute(
314
+ #execute = async (
222
315
  ...args: Parameters<TFn>
223
- ): Promise<ReturnType<TFn> | undefined> {
224
- if (!this.getEnabled() || this._isExecuting) return undefined
225
- this._abortController = new AbortController()
316
+ ): Promise<ReturnType<TFn> | undefined> => {
317
+ if (!this.#getEnabled() || this.store.state.isExecuting) return undefined
318
+ this.#abortController = new AbortController()
226
319
  try {
227
- this._isExecuting = true
228
- this._lastResult = await this.fn(...args) // EXECUTE!
229
- this._successCount++
230
- this._options.onSuccess?.(this._lastResult!, this)
320
+ this.#setState({ isExecuting: true })
321
+ const result = await this.fn(...args) // EXECUTE!
322
+ this.#setState({
323
+ lastResult: result,
324
+ successCount: this.store.state.successCount + 1,
325
+ })
326
+ this.options.onSuccess?.(result, this)
231
327
  } catch (error) {
232
- this._errorCount++
233
- this._options.onError?.(error, this)
234
- if (this._options.throwOnError) {
328
+ this.#setState({
329
+ errorCount: this.store.state.errorCount + 1,
330
+ })
331
+ this.options.onError?.(error, this)
332
+ if (this.options.throwOnError) {
235
333
  throw error
236
334
  } else {
237
335
  console.error(error)
238
336
  }
239
337
  } finally {
240
- this._isExecuting = false
241
- this._settleCount++
242
- this._abortController = null
243
- this._lastExecutionTime = Date.now()
244
- this._nextExecutionTime = this._lastExecutionTime + this.getWait()
245
- this._options.onSettled?.(this)
246
- }
247
- return this._lastResult
248
- }
249
-
250
- private resolvePreviousPromise(): void {
251
- if (this._resolvePreviousPromise) {
252
- this._resolvePreviousPromise(this._lastResult)
253
- this._resolvePreviousPromise = null
338
+ const lastExecutionTime = Date.now()
339
+ const nextExecutionTime = lastExecutionTime + this.#getWait()
340
+ this.#setState({
341
+ isExecuting: false,
342
+ isPending: false,
343
+ settleCount: this.store.state.settleCount + 1,
344
+ lastExecutionTime,
345
+ nextExecutionTime,
346
+ })
347
+ this.#abortController = null
348
+ this.options.onSettled?.(this)
254
349
  }
350
+ return this.store.state.lastResult
255
351
  }
256
352
 
257
353
  /**
258
- * Cancels any pending execution or aborts any execution in progress
354
+ * Processes the current pending execution immediately
259
355
  */
260
- cancel(): void {
261
- if (this._timeoutId) {
262
- clearTimeout(this._timeoutId)
263
- this._timeoutId = null
264
- }
265
- if (this._abortController) {
266
- this._abortController.abort()
267
- this._abortController = null
356
+ flush = (): void => {
357
+ if (this.store.state.isPending && this.store.state.lastArgs) {
358
+ this.#abortExecution() // abort any current execution
359
+ this.#clearTimeout() // clear any existing timeout
360
+ this.#execute(...this.store.state.lastArgs)
268
361
  }
269
- this.resolvePreviousPromise()
270
- this._lastArgs = undefined
271
- }
272
-
273
- /**
274
- * Returns the last execution time
275
- */
276
- getLastExecutionTime(): number {
277
- return this._lastExecutionTime
278
362
  }
279
363
 
280
- /**
281
- * Returns the next execution time
282
- */
283
- getNextExecutionTime(): number {
284
- return this._nextExecutionTime
285
- }
286
-
287
- /**
288
- * Returns the last result of the debounced function
289
- */
290
- getLastResult(): ReturnType<TFn> | undefined {
291
- return this._lastResult
364
+ #resolvePreviousPromiseInternal = (): void => {
365
+ if (this.#resolvePreviousPromise) {
366
+ this.#resolvePreviousPromise(this.store.state.lastResult)
367
+ this.#resolvePreviousPromise = null
368
+ }
292
369
  }
293
370
 
294
- /**
295
- * Returns the number of times the function has been executed successfully
296
- */
297
- getSuccessCount(): number {
298
- return this._successCount
371
+ #clearTimeout = (): void => {
372
+ if (this.#timeoutId) {
373
+ clearTimeout(this.#timeoutId)
374
+ this.#timeoutId = null
375
+ }
299
376
  }
300
377
 
301
- /**
302
- * Returns the number of times the function has settled (completed or errored)
303
- */
304
- getSettleCount(): number {
305
- return this._settleCount
378
+ #cancelPendingExecution = (): void => {
379
+ this.#clearTimeout()
380
+ if (this.#resolvePreviousPromise) {
381
+ this.#resolvePreviousPromise(this.store.state.lastResult)
382
+ this.#resolvePreviousPromise = null
383
+ }
384
+ this.#setState({
385
+ isPending: false,
386
+ isExecuting: false,
387
+ lastArgs: undefined,
388
+ })
306
389
  }
307
390
 
308
- /**
309
- * Returns the number of times the function has errored
310
- */
311
- getErrorCount(): number {
312
- return this._errorCount
391
+ #abortExecution = (): void => {
392
+ if (this.#abortController) {
393
+ this.#abortController.abort()
394
+ this.#abortController = null
395
+ }
313
396
  }
314
397
 
315
398
  /**
316
- * Returns the current pending state
399
+ * Cancels any pending execution or aborts any execution in progress
317
400
  */
318
- getIsPending(): boolean {
319
- return this.getEnabled() && !!this._timeoutId
401
+ cancel = (): void => {
402
+ this.#cancelPendingExecution()
403
+ this.#abortExecution()
320
404
  }
321
405
 
322
406
  /**
323
- * Returns the current executing state
407
+ * Resets the debouncer state to its default values
324
408
  */
325
- getIsExecuting(): boolean {
326
- return this._isExecuting
409
+ reset = (): void => {
410
+ this.#setState(getDefaultAsyncThrottlerState<TFn>())
327
411
  }
328
412
  }
329
413
 
@@ -343,6 +427,16 @@ export class AsyncThrottler<TFn extends AnyAsyncFunction> {
343
427
  * - Both onError and throwOnError can be used together - the handler will be called before any error is thrown
344
428
  * - The error state can be checked using the underlying AsyncThrottler instance
345
429
  *
430
+ * State Management:
431
+ * - Uses TanStack Store for reactive state management
432
+ * - Use `initialState` to provide initial state values when creating the async throttler
433
+ * - Use `onSuccess` callback to react to successful function execution and implement custom logic
434
+ * - Use `onError` callback to react to function execution errors and implement custom error handling
435
+ * - Use `onSettled` callback to react to function execution completion (success or error) and implement custom logic
436
+ * - The state includes error count, execution status, last execution time, and success/settle counts
437
+ * - State can be accessed via the underlying AsyncThrottler instance's `store.state` property
438
+ * - When using framework adapters (React/Solid), state is accessed from the hook's state property
439
+ *
346
440
  * @example
347
441
  * ```ts
348
442
  * const throttled = asyncThrottle(async (value: string) => {
@@ -365,5 +459,5 @@ export function asyncThrottle<TFn extends AnyAsyncFunction>(
365
459
  initialOptions: AsyncThrottlerOptions<TFn>,
366
460
  ) {
367
461
  const asyncThrottler = new AsyncThrottler(fn, initialOptions)
368
- return asyncThrottler.maybeExecute.bind(asyncThrottler)
462
+ return asyncThrottler.maybeExecute
369
463
  }