@tanstack/solid-pacer 0.2.0
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.
- package/LICENSE +21 -0
- package/dist/cjs/async-debouncer/createAsyncDebouncer.cjs +32 -0
- package/dist/cjs/async-debouncer/createAsyncDebouncer.cjs.map +1 -0
- package/dist/cjs/async-debouncer/createAsyncDebouncer.d.cts +42 -0
- package/dist/cjs/async-debouncer/index.cjs +12 -0
- package/dist/cjs/async-debouncer/index.cjs.map +1 -0
- package/dist/cjs/async-debouncer/index.d.cts +2 -0
- package/dist/cjs/async-queuer/createAsyncQueuer.cjs +69 -0
- package/dist/cjs/async-queuer/createAsyncQueuer.cjs.map +1 -0
- package/dist/cjs/async-queuer/createAsyncQueuer.d.cts +90 -0
- package/dist/cjs/async-queuer/index.cjs +12 -0
- package/dist/cjs/async-queuer/index.cjs.map +1 -0
- package/dist/cjs/async-queuer/index.d.cts +2 -0
- package/dist/cjs/async-rate-limiter/createAsyncRateLimiter.cjs +50 -0
- package/dist/cjs/async-rate-limiter/createAsyncRateLimiter.cjs.map +1 -0
- package/dist/cjs/async-rate-limiter/createAsyncRateLimiter.d.cts +46 -0
- package/dist/cjs/async-rate-limiter/index.cjs +12 -0
- package/dist/cjs/async-rate-limiter/index.cjs.map +1 -0
- package/dist/cjs/async-rate-limiter/index.d.cts +2 -0
- package/dist/cjs/async-throttler/createAsyncThrottler.cjs +42 -0
- package/dist/cjs/async-throttler/createAsyncThrottler.cjs.map +1 -0
- package/dist/cjs/async-throttler/createAsyncThrottler.d.cts +46 -0
- package/dist/cjs/async-throttler/index.cjs +12 -0
- package/dist/cjs/async-throttler/index.cjs.map +1 -0
- package/dist/cjs/async-throttler/index.d.cts +2 -0
- package/dist/cjs/compare/index.cjs +10 -0
- package/dist/cjs/compare/index.cjs.map +1 -0
- package/dist/cjs/compare/index.d.cts +1 -0
- package/dist/cjs/debouncer/createDebouncedSignal.cjs +11 -0
- package/dist/cjs/debouncer/createDebouncedSignal.cjs.map +1 -0
- package/dist/cjs/debouncer/createDebouncedSignal.d.cts +47 -0
- package/dist/cjs/debouncer/createDebouncedValue.cjs +19 -0
- package/dist/cjs/debouncer/createDebouncedValue.cjs.map +1 -0
- package/dist/cjs/debouncer/createDebouncedValue.d.cts +44 -0
- package/dist/cjs/debouncer/createDebouncer.cjs +32 -0
- package/dist/cjs/debouncer/createDebouncer.cjs.map +1 -0
- package/dist/cjs/debouncer/createDebouncer.d.cts +47 -0
- package/dist/cjs/debouncer/index.cjs +16 -0
- package/dist/cjs/debouncer/index.cjs.map +1 -0
- package/dist/cjs/debouncer/index.d.cts +4 -0
- package/dist/cjs/index.cjs +38 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/index.d.cts +18 -0
- package/dist/cjs/queuer/createQueuer.cjs +66 -0
- package/dist/cjs/queuer/createQueuer.cjs.map +1 -0
- package/dist/cjs/queuer/createQueuer.d.cts +82 -0
- package/dist/cjs/queuer/index.cjs +12 -0
- package/dist/cjs/queuer/index.cjs.map +1 -0
- package/dist/cjs/queuer/index.d.cts +2 -0
- package/dist/cjs/rate-limiter/createRateLimitedSignal.cjs +15 -0
- package/dist/cjs/rate-limiter/createRateLimitedSignal.cjs.map +1 -0
- package/dist/cjs/rate-limiter/createRateLimitedSignal.d.cts +58 -0
- package/dist/cjs/rate-limiter/createRateLimitedValue.cjs +13 -0
- package/dist/cjs/rate-limiter/createRateLimitedValue.cjs.map +1 -0
- package/dist/cjs/rate-limiter/createRateLimitedValue.d.cts +51 -0
- package/dist/cjs/rate-limiter/createRateLimiter.cjs +50 -0
- package/dist/cjs/rate-limiter/createRateLimiter.cjs.map +1 -0
- package/dist/cjs/rate-limiter/createRateLimiter.d.cts +49 -0
- package/dist/cjs/rate-limiter/index.cjs +16 -0
- package/dist/cjs/rate-limiter/index.cjs.map +1 -0
- package/dist/cjs/rate-limiter/index.d.cts +4 -0
- package/dist/cjs/throttler/createThrottledSignal.cjs +11 -0
- package/dist/cjs/throttler/createThrottledSignal.cjs.map +1 -0
- package/dist/cjs/throttler/createThrottledSignal.d.cts +42 -0
- package/dist/cjs/throttler/createThrottledValue.cjs +19 -0
- package/dist/cjs/throttler/createThrottledValue.cjs.map +1 -0
- package/dist/cjs/throttler/createThrottledValue.d.cts +36 -0
- package/dist/cjs/throttler/createThrottler.cjs +42 -0
- package/dist/cjs/throttler/createThrottler.cjs.map +1 -0
- package/dist/cjs/throttler/createThrottler.d.cts +47 -0
- package/dist/cjs/throttler/index.cjs +16 -0
- package/dist/cjs/throttler/index.cjs.map +1 -0
- package/dist/cjs/throttler/index.d.cts +4 -0
- package/dist/cjs/types/index.cjs +10 -0
- package/dist/cjs/types/index.cjs.map +1 -0
- package/dist/cjs/types/index.d.cts +1 -0
- package/dist/cjs/utils/index.cjs +10 -0
- package/dist/cjs/utils/index.cjs.map +1 -0
- package/dist/cjs/utils/index.d.cts +1 -0
- package/dist/esm/async-debouncer/createAsyncDebouncer.d.ts +42 -0
- package/dist/esm/async-debouncer/createAsyncDebouncer.js +32 -0
- package/dist/esm/async-debouncer/createAsyncDebouncer.js.map +1 -0
- package/dist/esm/async-debouncer/index.d.ts +2 -0
- package/dist/esm/async-debouncer/index.js +6 -0
- package/dist/esm/async-debouncer/index.js.map +1 -0
- package/dist/esm/async-queuer/createAsyncQueuer.d.ts +90 -0
- package/dist/esm/async-queuer/createAsyncQueuer.js +69 -0
- package/dist/esm/async-queuer/createAsyncQueuer.js.map +1 -0
- package/dist/esm/async-queuer/index.d.ts +2 -0
- package/dist/esm/async-queuer/index.js +6 -0
- package/dist/esm/async-queuer/index.js.map +1 -0
- package/dist/esm/async-rate-limiter/createAsyncRateLimiter.d.ts +46 -0
- package/dist/esm/async-rate-limiter/createAsyncRateLimiter.js +50 -0
- package/dist/esm/async-rate-limiter/createAsyncRateLimiter.js.map +1 -0
- package/dist/esm/async-rate-limiter/index.d.ts +2 -0
- package/dist/esm/async-rate-limiter/index.js +6 -0
- package/dist/esm/async-rate-limiter/index.js.map +1 -0
- package/dist/esm/async-throttler/createAsyncThrottler.d.ts +46 -0
- package/dist/esm/async-throttler/createAsyncThrottler.js +42 -0
- package/dist/esm/async-throttler/createAsyncThrottler.js.map +1 -0
- package/dist/esm/async-throttler/index.d.ts +2 -0
- package/dist/esm/async-throttler/index.js +6 -0
- package/dist/esm/async-throttler/index.js.map +1 -0
- package/dist/esm/compare/index.d.ts +1 -0
- package/dist/esm/compare/index.js +2 -0
- package/dist/esm/compare/index.js.map +1 -0
- package/dist/esm/debouncer/createDebouncedSignal.d.ts +47 -0
- package/dist/esm/debouncer/createDebouncedSignal.js +11 -0
- package/dist/esm/debouncer/createDebouncedSignal.js.map +1 -0
- package/dist/esm/debouncer/createDebouncedValue.d.ts +44 -0
- package/dist/esm/debouncer/createDebouncedValue.js +19 -0
- package/dist/esm/debouncer/createDebouncedValue.js.map +1 -0
- package/dist/esm/debouncer/createDebouncer.d.ts +47 -0
- package/dist/esm/debouncer/createDebouncer.js +32 -0
- package/dist/esm/debouncer/createDebouncer.js.map +1 -0
- package/dist/esm/debouncer/index.d.ts +4 -0
- package/dist/esm/debouncer/index.js +10 -0
- package/dist/esm/debouncer/index.js.map +1 -0
- package/dist/esm/index.d.ts +18 -0
- package/dist/esm/index.js +32 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/queuer/createQueuer.d.ts +82 -0
- package/dist/esm/queuer/createQueuer.js +66 -0
- package/dist/esm/queuer/createQueuer.js.map +1 -0
- package/dist/esm/queuer/index.d.ts +2 -0
- package/dist/esm/queuer/index.js +6 -0
- package/dist/esm/queuer/index.js.map +1 -0
- package/dist/esm/rate-limiter/createRateLimitedSignal.d.ts +58 -0
- package/dist/esm/rate-limiter/createRateLimitedSignal.js +15 -0
- package/dist/esm/rate-limiter/createRateLimitedSignal.js.map +1 -0
- package/dist/esm/rate-limiter/createRateLimitedValue.d.ts +51 -0
- package/dist/esm/rate-limiter/createRateLimitedValue.js +13 -0
- package/dist/esm/rate-limiter/createRateLimitedValue.js.map +1 -0
- package/dist/esm/rate-limiter/createRateLimiter.d.ts +49 -0
- package/dist/esm/rate-limiter/createRateLimiter.js +50 -0
- package/dist/esm/rate-limiter/createRateLimiter.js.map +1 -0
- package/dist/esm/rate-limiter/index.d.ts +4 -0
- package/dist/esm/rate-limiter/index.js +10 -0
- package/dist/esm/rate-limiter/index.js.map +1 -0
- package/dist/esm/throttler/createThrottledSignal.d.ts +42 -0
- package/dist/esm/throttler/createThrottledSignal.js +11 -0
- package/dist/esm/throttler/createThrottledSignal.js.map +1 -0
- package/dist/esm/throttler/createThrottledValue.d.ts +36 -0
- package/dist/esm/throttler/createThrottledValue.js +19 -0
- package/dist/esm/throttler/createThrottledValue.js.map +1 -0
- package/dist/esm/throttler/createThrottler.d.ts +47 -0
- package/dist/esm/throttler/createThrottler.js +42 -0
- package/dist/esm/throttler/createThrottler.js.map +1 -0
- package/dist/esm/throttler/index.d.ts +4 -0
- package/dist/esm/throttler/index.js +10 -0
- package/dist/esm/throttler/index.js.map +1 -0
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.js +2 -0
- package/dist/esm/types/index.js.map +1 -0
- package/dist/esm/utils/index.d.ts +1 -0
- package/dist/esm/utils/index.js +2 -0
- package/dist/esm/utils/index.js.map +1 -0
- package/package.json +163 -0
- package/src/async-debouncer/createAsyncDebouncer.ts +89 -0
- package/src/async-debouncer/index.ts +4 -0
- package/src/async-queuer/createAsyncQueuer.ts +175 -0
- package/src/async-queuer/index.ts +3 -0
- package/src/async-rate-limiter/createAsyncRateLimiter.ts +116 -0
- package/src/async-rate-limiter/index.ts +4 -0
- package/src/async-throttler/createAsyncThrottler.ts +106 -0
- package/src/async-throttler/index.ts +4 -0
- package/src/compare/index.ts +1 -0
- package/src/debouncer/createDebouncedSignal.ts +59 -0
- package/src/debouncer/createDebouncedValue.ts +64 -0
- package/src/debouncer/createDebouncer.ts +90 -0
- package/src/debouncer/index.ts +6 -0
- package/src/index.ts +36 -0
- package/src/queuer/createQueuer.ts +167 -0
- package/src/queuer/index.ts +3 -0
- package/src/rate-limiter/createRateLimitedSignal.ts +74 -0
- package/src/rate-limiter/createRateLimitedValue.ts +66 -0
- package/src/rate-limiter/createRateLimiter.ts +115 -0
- package/src/rate-limiter/index.ts +5 -0
- package/src/throttler/createThrottledSignal.ts +52 -0
- package/src/throttler/createThrottledValue.ts +56 -0
- package/src/throttler/createThrottler.ts +106 -0
- package/src/throttler/index.ts +6 -0
- package/src/types/index.ts +1 -0
- package/src/utils/index.ts +1 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { createSignal } from "solid-js";
|
|
2
|
+
import { createThrottler } from "./createThrottler.js";
|
|
3
|
+
function createThrottledSignal(value, initialOptions) {
|
|
4
|
+
const [throttledValue, setThrottledValue] = createSignal(value);
|
|
5
|
+
const throttler = createThrottler(setThrottledValue, initialOptions);
|
|
6
|
+
return [throttledValue, throttler.maybeExecute, throttler];
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
createThrottledSignal
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=createThrottledSignal.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createThrottledSignal.js","sources":["../../../src/throttler/createThrottledSignal.ts"],"sourcesContent":["import { createSignal } from 'solid-js'\nimport { createThrottler } from './createThrottler'\nimport type { SolidThrottler } from './createThrottler'\nimport type { Accessor, Setter } from 'solid-js'\nimport type { ThrottlerOptions } from '@tanstack/pacer/throttler'\n\n/**\n * A Solid hook that creates a throttled state value that updates at most once within a specified time window.\n * This hook combines Solid's createSignal with throttling functionality to provide controlled state updates.\n *\n * Throttling ensures state updates occur at a controlled rate regardless of how frequently the setter is called.\n * This is useful for rate-limiting expensive re-renders or operations that depend on rapidly changing state.\n *\n * The hook returns a tuple containing:\n * - The throttled state value accessor\n * - A throttled setter function that respects the configured wait time\n * - The throttler instance for additional control\n *\n * For more direct control over throttling without state management,\n * consider using the lower-level createThrottler hook instead.\n *\n * @example\n * ```tsx\n * // Basic throttling - update state at most once per second\n * const [value, setValue, throttler] = createThrottledSignal(0, { wait: 1000 });\n *\n * // With custom leading/trailing behavior\n * const [value, setValue] = createThrottledSignal(0, {\n * wait: 1000,\n * leading: true, // Update immediately on first change\n * trailing: false // Skip trailing edge updates\n * });\n *\n * // Access throttler state via signals\n * console.log('Executions:', throttler.executionCount());\n * console.log('Is pending:', throttler.isPending());\n * console.log('Last execution:', throttler.lastExecutionTime());\n * console.log('Next execution:', throttler.nextExecutionTime());\n * ```\n */\nexport function createThrottledSignal<TValue>(\n value: TValue,\n initialOptions: ThrottlerOptions<Setter<TValue>, [Accessor<TValue>]>,\n): [\n Accessor<TValue>,\n Setter<TValue>,\n SolidThrottler<Setter<TValue>, [Accessor<TValue>]>,\n] {\n const [throttledValue, setThrottledValue] = createSignal<TValue>(value)\n const throttler = createThrottler(setThrottledValue, initialOptions)\n return [throttledValue, throttler.maybeExecute as Setter<TValue>, throttler]\n}\n"],"names":[],"mappings":";;AAwCgB,SAAA,sBACd,OACA,gBAKA;AACA,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,aAAqB,KAAK;AAChE,QAAA,YAAY,gBAAgB,mBAAmB,cAAc;AACnE,SAAO,CAAC,gBAAgB,UAAU,cAAgC,SAAS;AAC7E;"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { SolidThrottler } from './createThrottler.js';
|
|
2
|
+
import { Accessor, Setter } from 'solid-js';
|
|
3
|
+
import { ThrottlerOptions } from '@tanstack/pacer/throttler';
|
|
4
|
+
/**
|
|
5
|
+
* A high-level Solid hook that creates a throttled version of a value that updates at most once within a specified time window.
|
|
6
|
+
* This hook uses Solid's createSignal internally to manage the throttled state.
|
|
7
|
+
*
|
|
8
|
+
* Throttling ensures the value updates occur at a controlled rate regardless of how frequently the input value changes.
|
|
9
|
+
* This is useful for rate-limiting expensive re-renders or API calls that depend on rapidly changing values.
|
|
10
|
+
*
|
|
11
|
+
* The hook returns both the throttled value and the underlying throttler instance for additional control.
|
|
12
|
+
* The throttled value will update according to the leading/trailing edge behavior specified in the options.
|
|
13
|
+
*
|
|
14
|
+
* For more direct control over throttling behavior without Solid state management,
|
|
15
|
+
* consider using the lower-level createThrottler hook instead.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* // Basic throttling - update at most once per second
|
|
20
|
+
* const [throttledValue] = createThrottledValue(rawValue, { wait: 1000 });
|
|
21
|
+
*
|
|
22
|
+
* // With custom leading/trailing behavior
|
|
23
|
+
* const [throttledValue, throttler] = createThrottledValue(rawValue, {
|
|
24
|
+
* wait: 1000,
|
|
25
|
+
* leading: true, // Update immediately on first change
|
|
26
|
+
* trailing: false // Skip trailing edge updates
|
|
27
|
+
* });
|
|
28
|
+
*
|
|
29
|
+
* // Access throttler state via signals
|
|
30
|
+
* console.log('Executions:', throttler.executionCount());
|
|
31
|
+
* console.log('Is pending:', throttler.isPending());
|
|
32
|
+
* console.log('Last execution:', throttler.lastExecutionTime());
|
|
33
|
+
* console.log('Next execution:', throttler.nextExecutionTime());
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare function createThrottledValue<TValue>(value: Accessor<TValue>, initialOptions: ThrottlerOptions<Setter<TValue>, [Accessor<TValue>]>): [Accessor<TValue>, SolidThrottler<Setter<TValue>, [Accessor<TValue>]>];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createEffect, onCleanup } from "solid-js";
|
|
2
|
+
import { createThrottledSignal } from "./createThrottledSignal.js";
|
|
3
|
+
function createThrottledValue(value, initialOptions) {
|
|
4
|
+
const [throttledValue, setThrottledValue, throttler] = createThrottledSignal(
|
|
5
|
+
value(),
|
|
6
|
+
initialOptions
|
|
7
|
+
);
|
|
8
|
+
createEffect(() => {
|
|
9
|
+
setThrottledValue(value());
|
|
10
|
+
onCleanup(() => {
|
|
11
|
+
throttler.cancel();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
return [throttledValue, throttler];
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
createThrottledValue
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=createThrottledValue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createThrottledValue.js","sources":["../../../src/throttler/createThrottledValue.ts"],"sourcesContent":["import { createEffect, onCleanup } from 'solid-js'\nimport { createThrottledSignal } from './createThrottledSignal'\nimport type { SolidThrottler } from './createThrottler'\nimport type { Accessor, Setter } from 'solid-js'\nimport type { ThrottlerOptions } from '@tanstack/pacer/throttler'\n\n/**\n * A high-level Solid hook that creates a throttled version of a value that updates at most once within a specified time window.\n * This hook uses Solid's createSignal internally to manage the throttled state.\n *\n * Throttling ensures the value updates occur at a controlled rate regardless of how frequently the input value changes.\n * This is useful for rate-limiting expensive re-renders or API calls that depend on rapidly changing values.\n *\n * The hook returns both the throttled value and the underlying throttler instance for additional control.\n * The throttled value will update according to the leading/trailing edge behavior specified in the options.\n *\n * For more direct control over throttling behavior without Solid state management,\n * consider using the lower-level createThrottler hook instead.\n *\n * @example\n * ```tsx\n * // Basic throttling - update at most once per second\n * const [throttledValue] = createThrottledValue(rawValue, { wait: 1000 });\n *\n * // With custom leading/trailing behavior\n * const [throttledValue, throttler] = createThrottledValue(rawValue, {\n * wait: 1000,\n * leading: true, // Update immediately on first change\n * trailing: false // Skip trailing edge updates\n * });\n *\n * // Access throttler state via signals\n * console.log('Executions:', throttler.executionCount());\n * console.log('Is pending:', throttler.isPending());\n * console.log('Last execution:', throttler.lastExecutionTime());\n * console.log('Next execution:', throttler.nextExecutionTime());\n * ```\n */\nexport function createThrottledValue<TValue>(\n value: Accessor<TValue>,\n initialOptions: ThrottlerOptions<Setter<TValue>, [Accessor<TValue>]>,\n): [Accessor<TValue>, SolidThrottler<Setter<TValue>, [Accessor<TValue>]>] {\n const [throttledValue, setThrottledValue, throttler] = createThrottledSignal(\n value(),\n initialOptions,\n )\n\n createEffect(() => {\n setThrottledValue(value() as any)\n onCleanup(() => {\n throttler.cancel()\n })\n })\n\n return [throttledValue, throttler]\n}\n"],"names":[],"mappings":";;AAsCgB,SAAA,qBACd,OACA,gBACwE;AACxE,QAAM,CAAC,gBAAgB,mBAAmB,SAAS,IAAI;AAAA,IACrD,MAAM;AAAA,IACN;AAAA,EACF;AAEA,eAAa,MAAM;AACjB,sBAAkB,OAAc;AAChC,cAAU,MAAM;AACd,gBAAU,OAAO;AAAA,IAAA,CAClB;AAAA,EAAA,CACF;AAEM,SAAA,CAAC,gBAAgB,SAAS;AACnC;"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Throttler, ThrottlerOptions } from '@tanstack/pacer/throttler';
|
|
2
|
+
import { Accessor } from 'solid-js';
|
|
3
|
+
import { AnyFunction } from '@tanstack/pacer/types';
|
|
4
|
+
/**
|
|
5
|
+
* An extension of the Throttler class that adds Solid signals to access the internal state of the throttler
|
|
6
|
+
*/
|
|
7
|
+
export interface SolidThrottler<TFn extends AnyFunction, TArgs extends Parameters<TFn>> extends Omit<Throttler<TFn, TArgs>, 'getExecutionCount' | 'getIsPending' | 'getLastExecutionTime' | 'getNextExecutionTime'> {
|
|
8
|
+
executionCount: Accessor<number>;
|
|
9
|
+
isPending: Accessor<boolean>;
|
|
10
|
+
lastExecutionTime: Accessor<number>;
|
|
11
|
+
nextExecutionTime: Accessor<number>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A low-level Solid hook that creates a `Throttler` instance that limits how often the provided function can execute.
|
|
15
|
+
*
|
|
16
|
+
* This hook is designed to be flexible and state-management agnostic - it simply returns a throttler instance that
|
|
17
|
+
* you can integrate with any state management solution (createSignal, Redux, Zustand, Jotai, etc). For a simpler and higher-level hook that
|
|
18
|
+
* integrates directly with Solid's createSignal, see createThrottledSignal.
|
|
19
|
+
*
|
|
20
|
+
* Throttling ensures a function executes at most once within a specified time window,
|
|
21
|
+
* regardless of how many times it is called. This is useful for rate-limiting
|
|
22
|
+
* expensive operations or UI updates.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* // Basic throttling with custom state
|
|
27
|
+
* const [value, setValue] = createSignal(0);
|
|
28
|
+
* const throttler = createThrottler(setValue, { wait: 1000 });
|
|
29
|
+
*
|
|
30
|
+
* // With any state manager
|
|
31
|
+
* const throttler = createThrottler(
|
|
32
|
+
* (value) => stateManager.setState(value),
|
|
33
|
+
* {
|
|
34
|
+
* wait: 2000,
|
|
35
|
+
* leading: true, // Execute immediately on first call
|
|
36
|
+
* trailing: false // Skip trailing edge updates
|
|
37
|
+
* }
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* // Access throttler state via signals
|
|
41
|
+
* console.log(throttler.executionCount()); // number of times executed
|
|
42
|
+
* console.log(throttler.isPending()); // whether throttled function is pending
|
|
43
|
+
* console.log(throttler.lastExecutionTime()); // timestamp of last execution
|
|
44
|
+
* console.log(throttler.nextExecutionTime()); // timestamp of next allowed execution
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare function createThrottler<TFn extends AnyFunction, TArgs extends Parameters<TFn>>(fn: TFn, initialOptions: ThrottlerOptions<TFn, TArgs>): SolidThrottler<TFn, TArgs>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Throttler } from "@tanstack/pacer/throttler";
|
|
2
|
+
import { createSignal } from "solid-js";
|
|
3
|
+
import { bindInstanceMethods } from "@tanstack/pacer/utils";
|
|
4
|
+
function createThrottler(fn, initialOptions) {
|
|
5
|
+
const throttler = new Throttler(fn, initialOptions);
|
|
6
|
+
const [executionCount, setExecutionCount] = createSignal(
|
|
7
|
+
throttler.getExecutionCount()
|
|
8
|
+
);
|
|
9
|
+
const [isPending, setIsPending] = createSignal(throttler.getIsPending());
|
|
10
|
+
const [lastExecutionTime, setLastExecutionTime] = createSignal(
|
|
11
|
+
throttler.getLastExecutionTime()
|
|
12
|
+
);
|
|
13
|
+
const [nextExecutionTime, setNextExecutionTime] = createSignal(
|
|
14
|
+
throttler.getNextExecutionTime()
|
|
15
|
+
);
|
|
16
|
+
function setOptions(newOptions) {
|
|
17
|
+
throttler.setOptions({
|
|
18
|
+
...newOptions,
|
|
19
|
+
onExecute: (throttler2) => {
|
|
20
|
+
setExecutionCount(throttler2.getExecutionCount());
|
|
21
|
+
setIsPending(throttler2.getIsPending());
|
|
22
|
+
setLastExecutionTime(throttler2.getLastExecutionTime());
|
|
23
|
+
setNextExecutionTime(throttler2.getNextExecutionTime());
|
|
24
|
+
const onExecute = newOptions.onExecute ?? initialOptions.onExecute;
|
|
25
|
+
onExecute == null ? void 0 : onExecute(throttler2);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
setOptions(initialOptions);
|
|
30
|
+
return {
|
|
31
|
+
...bindInstanceMethods(throttler),
|
|
32
|
+
executionCount,
|
|
33
|
+
isPending,
|
|
34
|
+
lastExecutionTime,
|
|
35
|
+
nextExecutionTime,
|
|
36
|
+
setOptions
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
export {
|
|
40
|
+
createThrottler
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=createThrottler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createThrottler.js","sources":["../../../src/throttler/createThrottler.ts"],"sourcesContent":["import { Throttler } from '@tanstack/pacer/throttler'\nimport { createSignal } from 'solid-js'\nimport { bindInstanceMethods } from '@tanstack/pacer/utils'\nimport type { Accessor } from 'solid-js'\nimport type { AnyFunction } from '@tanstack/pacer/types'\nimport type { ThrottlerOptions } from '@tanstack/pacer/throttler'\n\n/**\n * An extension of the Throttler class that adds Solid signals to access the internal state of the throttler\n */\nexport interface SolidThrottler<\n TFn extends AnyFunction,\n TArgs extends Parameters<TFn>,\n> extends Omit<\n Throttler<TFn, TArgs>,\n | 'getExecutionCount'\n | 'getIsPending'\n | 'getLastExecutionTime'\n | 'getNextExecutionTime'\n > {\n executionCount: Accessor<number>\n isPending: Accessor<boolean>\n lastExecutionTime: Accessor<number>\n nextExecutionTime: Accessor<number>\n}\n\n/**\n * A low-level Solid hook that creates a `Throttler` instance that limits how often the provided function can execute.\n *\n * This hook is designed to be flexible and state-management agnostic - it simply returns a throttler instance that\n * you can integrate with any state management solution (createSignal, Redux, Zustand, Jotai, etc). For a simpler and higher-level hook that\n * integrates directly with Solid's createSignal, see createThrottledSignal.\n *\n * Throttling ensures a function executes at most once within a specified time window,\n * regardless of how many times it is called. This is useful for rate-limiting\n * expensive operations or UI updates.\n *\n * @example\n * ```tsx\n * // Basic throttling with custom state\n * const [value, setValue] = createSignal(0);\n * const throttler = createThrottler(setValue, { wait: 1000 });\n *\n * // With any state manager\n * const throttler = createThrottler(\n * (value) => stateManager.setState(value),\n * {\n * wait: 2000,\n * leading: true, // Execute immediately on first call\n * trailing: false // Skip trailing edge updates\n * }\n * );\n *\n * // Access throttler state via signals\n * console.log(throttler.executionCount()); // number of times executed\n * console.log(throttler.isPending()); // whether throttled function is pending\n * console.log(throttler.lastExecutionTime()); // timestamp of last execution\n * console.log(throttler.nextExecutionTime()); // timestamp of next allowed execution\n * ```\n */\nexport function createThrottler<\n TFn extends AnyFunction,\n TArgs extends Parameters<TFn>,\n>(\n fn: TFn,\n initialOptions: ThrottlerOptions<TFn, TArgs>,\n): SolidThrottler<TFn, TArgs> {\n const throttler = new Throttler<TFn, TArgs>(fn, initialOptions)\n\n const [executionCount, setExecutionCount] = createSignal(\n throttler.getExecutionCount(),\n )\n const [isPending, setIsPending] = createSignal(throttler.getIsPending())\n const [lastExecutionTime, setLastExecutionTime] = createSignal(\n throttler.getLastExecutionTime(),\n )\n const [nextExecutionTime, setNextExecutionTime] = createSignal(\n throttler.getNextExecutionTime(),\n )\n\n function setOptions(newOptions: Partial<ThrottlerOptions<TFn, TArgs>>) {\n throttler.setOptions({\n ...newOptions,\n onExecute: (throttler) => {\n setExecutionCount(throttler.getExecutionCount())\n setIsPending(throttler.getIsPending())\n setLastExecutionTime(throttler.getLastExecutionTime())\n setNextExecutionTime(throttler.getNextExecutionTime())\n\n const onExecute = newOptions.onExecute ?? initialOptions.onExecute\n onExecute?.(throttler)\n },\n })\n }\n\n setOptions(initialOptions)\n\n return {\n ...bindInstanceMethods(throttler),\n executionCount,\n isPending,\n lastExecutionTime,\n nextExecutionTime,\n setOptions,\n }\n}\n"],"names":["throttler"],"mappings":";;;AA4DgB,SAAA,gBAId,IACA,gBAC4B;AAC5B,QAAM,YAAY,IAAI,UAAsB,IAAI,cAAc;AAExD,QAAA,CAAC,gBAAgB,iBAAiB,IAAI;AAAA,IAC1C,UAAU,kBAAkB;AAAA,EAC9B;AACA,QAAM,CAAC,WAAW,YAAY,IAAI,aAAa,UAAU,cAAc;AACjE,QAAA,CAAC,mBAAmB,oBAAoB,IAAI;AAAA,IAChD,UAAU,qBAAqB;AAAA,EACjC;AACM,QAAA,CAAC,mBAAmB,oBAAoB,IAAI;AAAA,IAChD,UAAU,qBAAqB;AAAA,EACjC;AAEA,WAAS,WAAW,YAAmD;AACrE,cAAU,WAAW;AAAA,MACnB,GAAG;AAAA,MACH,WAAW,CAACA,eAAc;AACNA,0BAAAA,WAAU,mBAAmB;AAClCA,qBAAAA,WAAU,cAAc;AAChBA,6BAAAA,WAAU,sBAAsB;AAChCA,6BAAAA,WAAU,sBAAsB;AAE/C,cAAA,YAAY,WAAW,aAAa,eAAe;AACzD,+CAAYA;AAAAA,MAAS;AAAA,IACvB,CACD;AAAA,EAAA;AAGH,aAAW,cAAc;AAElB,SAAA;AAAA,IACL,GAAG,oBAAoB,SAAS;AAAA,IAChC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from "@tanstack/pacer/throttler";
|
|
2
|
+
import { createThrottledSignal } from "./createThrottledSignal.js";
|
|
3
|
+
import { createThrottledValue } from "./createThrottledValue.js";
|
|
4
|
+
import { createThrottler } from "./createThrottler.js";
|
|
5
|
+
export {
|
|
6
|
+
createThrottledSignal,
|
|
7
|
+
createThrottledValue,
|
|
8
|
+
createThrottler
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tanstack/pacer/types';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@tanstack/pacer/utils';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"}
|
package/package.json
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tanstack/solid-pacer",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Utilities for debouncing and throttling functions in Solid.",
|
|
5
|
+
"author": "Tanner Linsley",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/TanStack/pacer.git",
|
|
10
|
+
"directory": "packages/solid-pacer"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://tanstack.com/pacer",
|
|
13
|
+
"funding": {
|
|
14
|
+
"type": "github",
|
|
15
|
+
"url": "https://github.com/sponsors/tannerlinsley"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"solid",
|
|
19
|
+
"debounce",
|
|
20
|
+
"throttle",
|
|
21
|
+
"rate-limit",
|
|
22
|
+
"queue",
|
|
23
|
+
"async"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"types": "dist/esm/index.d.ts",
|
|
27
|
+
"main": "dist/cjs/index.cjs",
|
|
28
|
+
"module": "dist/esm/index.js",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/esm/index.d.ts",
|
|
33
|
+
"default": "./dist/esm/index.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/cjs/index.d.cts",
|
|
37
|
+
"default": "./dist/cjs/index.cjs"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"./async-debouncer": {
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/esm/async-debouncer/index.d.ts",
|
|
43
|
+
"default": "./dist/esm/async-debouncer/index.js"
|
|
44
|
+
},
|
|
45
|
+
"require": {
|
|
46
|
+
"types": "./dist/cjs/async-debouncer/index.d.cts",
|
|
47
|
+
"default": "./dist/cjs/async-debouncer/index.cjs"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"./async-queuer": {
|
|
51
|
+
"import": {
|
|
52
|
+
"types": "./dist/esm/async-queuer/index.d.ts",
|
|
53
|
+
"default": "./dist/esm/async-queuer/index.js"
|
|
54
|
+
},
|
|
55
|
+
"require": {
|
|
56
|
+
"types": "./dist/cjs/async-queuer/index.d.cts",
|
|
57
|
+
"default": "./dist/cjs/async-queuer/index.cjs"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"./async-rate-limiter": {
|
|
61
|
+
"import": {
|
|
62
|
+
"types": "./dist/esm/async-rate-limiter/index.d.ts",
|
|
63
|
+
"default": "./dist/esm/async-rate-limiter/index.js"
|
|
64
|
+
},
|
|
65
|
+
"require": {
|
|
66
|
+
"types": "./dist/cjs/async-rate-limiter/index.d.cts",
|
|
67
|
+
"default": "./dist/cjs/async-rate-limiter/index.cjs"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"./async-throttler": {
|
|
71
|
+
"import": {
|
|
72
|
+
"types": "./dist/esm/async-throttler/index.d.ts",
|
|
73
|
+
"default": "./dist/esm/async-throttler/index.js"
|
|
74
|
+
},
|
|
75
|
+
"require": {
|
|
76
|
+
"types": "./dist/cjs/async-throttler/index.d.cts",
|
|
77
|
+
"default": "./dist/cjs/async-throttler/index.cjs"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"./debouncer": {
|
|
81
|
+
"import": {
|
|
82
|
+
"types": "./dist/esm/debouncer/index.d.ts",
|
|
83
|
+
"default": "./dist/esm/debouncer/index.js"
|
|
84
|
+
},
|
|
85
|
+
"require": {
|
|
86
|
+
"types": "./dist/cjs/debouncer/index.d.cts",
|
|
87
|
+
"default": "./dist/cjs/debouncer/index.cjs"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"./queuer": {
|
|
91
|
+
"import": {
|
|
92
|
+
"types": "./dist/esm/queuer/index.d.ts",
|
|
93
|
+
"default": "./dist/esm/queuer/index.js"
|
|
94
|
+
},
|
|
95
|
+
"require": {
|
|
96
|
+
"types": "./dist/cjs/queuer/index.d.cts",
|
|
97
|
+
"default": "./dist/cjs/queuer/index.cjs"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"./rate-limiter": {
|
|
101
|
+
"import": {
|
|
102
|
+
"types": "./dist/esm/rate-limiter/index.d.ts",
|
|
103
|
+
"default": "./dist/esm/rate-limiter/index.js"
|
|
104
|
+
},
|
|
105
|
+
"require": {
|
|
106
|
+
"types": "./dist/cjs/rate-limiter/index.d.cts",
|
|
107
|
+
"default": "./dist/cjs/rate-limiter/index.cjs"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"./throttler": {
|
|
111
|
+
"import": {
|
|
112
|
+
"types": "./dist/esm/throttler/index.d.ts",
|
|
113
|
+
"default": "./dist/esm/throttler/index.js"
|
|
114
|
+
},
|
|
115
|
+
"require": {
|
|
116
|
+
"types": "./dist/cjs/throttler/index.d.cts",
|
|
117
|
+
"default": "./dist/cjs/throttler/index.cjs"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
"./types": {
|
|
121
|
+
"types": "./dist/esm/types/index.d.ts",
|
|
122
|
+
"default": "./dist/esm/types/index.js"
|
|
123
|
+
},
|
|
124
|
+
"./utils": {
|
|
125
|
+
"import": {
|
|
126
|
+
"types": "./dist/esm/utils/index.d.ts",
|
|
127
|
+
"default": "./dist/esm/utils/index.js"
|
|
128
|
+
},
|
|
129
|
+
"require": {
|
|
130
|
+
"types": "./dist/cjs/utils/index.d.cts",
|
|
131
|
+
"default": "./dist/cjs/utils/index.cjs"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"./package.json": "./package.json"
|
|
135
|
+
},
|
|
136
|
+
"sideEffects": false,
|
|
137
|
+
"engines": {
|
|
138
|
+
"node": ">=18"
|
|
139
|
+
},
|
|
140
|
+
"files": [
|
|
141
|
+
"dist",
|
|
142
|
+
"src"
|
|
143
|
+
],
|
|
144
|
+
"dependencies": {
|
|
145
|
+
"@tanstack/pacer": "0.2.0"
|
|
146
|
+
},
|
|
147
|
+
"devDependencies": {
|
|
148
|
+
"solid-js": "^1.9.5",
|
|
149
|
+
"vite-plugin-solid": "^2.11.6"
|
|
150
|
+
},
|
|
151
|
+
"peerDependencies": {
|
|
152
|
+
"solid-js": ">=1.9.5"
|
|
153
|
+
},
|
|
154
|
+
"scripts": {
|
|
155
|
+
"clean": "premove ./build ./dist",
|
|
156
|
+
"test:eslint": "eslint ./src",
|
|
157
|
+
"test:lib": "vitest --passWithNoTests",
|
|
158
|
+
"test:lib:dev": "pnpm test:lib --watch",
|
|
159
|
+
"test:types": "tsc",
|
|
160
|
+
"test:build": "publint --strict",
|
|
161
|
+
"build": "vite build"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { AsyncDebouncer } from '@tanstack/pacer/async-debouncer'
|
|
2
|
+
import { createSignal } from 'solid-js'
|
|
3
|
+
import { bindInstanceMethods } from '@tanstack/pacer/utils'
|
|
4
|
+
import type { AsyncDebouncerOptions } from '@tanstack/pacer/async-debouncer'
|
|
5
|
+
import type { AnyAsyncFunction } from '@tanstack/pacer/types'
|
|
6
|
+
import type { Accessor } from 'solid-js'
|
|
7
|
+
|
|
8
|
+
export interface SolidAsyncDebouncer<
|
|
9
|
+
TFn extends AnyAsyncFunction,
|
|
10
|
+
TArgs extends Parameters<TFn>,
|
|
11
|
+
> extends Omit<
|
|
12
|
+
AsyncDebouncer<TFn, TArgs>,
|
|
13
|
+
'getExecutionCount' | 'getIsPending'
|
|
14
|
+
> {
|
|
15
|
+
executionCount: Accessor<number>
|
|
16
|
+
isPending: Accessor<boolean>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A low-level Solid hook that creates an `AsyncDebouncer` instance to delay execution of an async function.
|
|
21
|
+
*
|
|
22
|
+
* This hook is designed to be flexible and state-management agnostic - it simply returns a debouncer instance that
|
|
23
|
+
* you can integrate with any state management solution (createSignal, etc).
|
|
24
|
+
*
|
|
25
|
+
* Async debouncing ensures that an async function only executes after a specified delay has passed since its last invocation.
|
|
26
|
+
* This is useful for handling fast-changing inputs like search fields, form validation, or any scenario where you want to
|
|
27
|
+
* wait for user input to settle before making expensive async calls.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* // Basic API call debouncing
|
|
32
|
+
* const { maybeExecute } = createAsyncDebouncer(
|
|
33
|
+
* async (query: string) => {
|
|
34
|
+
* const results = await api.search(query);
|
|
35
|
+
* return results;
|
|
36
|
+
* },
|
|
37
|
+
* { wait: 500 }
|
|
38
|
+
* );
|
|
39
|
+
*
|
|
40
|
+
* // With state management
|
|
41
|
+
* const [results, setResults] = createSignal([]);
|
|
42
|
+
* const { maybeExecute } = createAsyncDebouncer(
|
|
43
|
+
* async (searchTerm) => {
|
|
44
|
+
* const data = await searchAPI(searchTerm);
|
|
45
|
+
* setResults(data);
|
|
46
|
+
* },
|
|
47
|
+
* {
|
|
48
|
+
* wait: 300,
|
|
49
|
+
* }
|
|
50
|
+
* );
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
export function createAsyncDebouncer<
|
|
55
|
+
TFn extends AnyAsyncFunction,
|
|
56
|
+
TArgs extends Parameters<TFn>,
|
|
57
|
+
>(
|
|
58
|
+
fn: TFn,
|
|
59
|
+
initialOptions: AsyncDebouncerOptions<TFn, TArgs>,
|
|
60
|
+
): SolidAsyncDebouncer<TFn, TArgs> {
|
|
61
|
+
const asyncDebouncer = new AsyncDebouncer<TFn, TArgs>(fn, initialOptions)
|
|
62
|
+
|
|
63
|
+
const [executionCount, setExecutionCount] = createSignal(
|
|
64
|
+
asyncDebouncer.getExecutionCount(),
|
|
65
|
+
)
|
|
66
|
+
const [isPending, setIsPending] = createSignal(asyncDebouncer.getIsPending())
|
|
67
|
+
|
|
68
|
+
function setOptions(newOptions: Partial<AsyncDebouncerOptions<TFn, TArgs>>) {
|
|
69
|
+
asyncDebouncer.setOptions({
|
|
70
|
+
...newOptions,
|
|
71
|
+
onExecute: (asyncDebouncer) => {
|
|
72
|
+
setExecutionCount(asyncDebouncer.getExecutionCount())
|
|
73
|
+
setIsPending(asyncDebouncer.getIsPending())
|
|
74
|
+
|
|
75
|
+
const onExecute = newOptions.onExecute ?? initialOptions.onExecute
|
|
76
|
+
onExecute?.(asyncDebouncer)
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
setOptions(initialOptions)
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
...bindInstanceMethods(asyncDebouncer),
|
|
85
|
+
executionCount,
|
|
86
|
+
isPending,
|
|
87
|
+
setOptions,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { AsyncQueuer } from '@tanstack/pacer/async-queuer'
|
|
2
|
+
import { createSignal } from 'solid-js'
|
|
3
|
+
import { bindInstanceMethods } from '@tanstack/pacer/utils'
|
|
4
|
+
import type { Accessor } from 'solid-js'
|
|
5
|
+
import type { AsyncQueuerOptions } from '@tanstack/pacer/async-queuer'
|
|
6
|
+
|
|
7
|
+
export interface SolidAsyncQueuer<TValue>
|
|
8
|
+
extends Omit<
|
|
9
|
+
AsyncQueuer<TValue>,
|
|
10
|
+
| 'getActiveItems'
|
|
11
|
+
| 'getAllItems'
|
|
12
|
+
| 'getExecutionCount'
|
|
13
|
+
| 'getIsEmpty'
|
|
14
|
+
| 'getIsFull'
|
|
15
|
+
| 'getIsIdle'
|
|
16
|
+
| 'getIsRunning'
|
|
17
|
+
| 'getPeek'
|
|
18
|
+
| 'getPendingItems'
|
|
19
|
+
| 'getSize'
|
|
20
|
+
> {
|
|
21
|
+
/**
|
|
22
|
+
* Signal version of `getActiveItems`
|
|
23
|
+
*/
|
|
24
|
+
activeItems: Accessor<Array<() => Promise<TValue>>>
|
|
25
|
+
/**
|
|
26
|
+
* Signal version of `getAllItems`
|
|
27
|
+
*/
|
|
28
|
+
allItems: Accessor<Array<() => Promise<TValue>>>
|
|
29
|
+
/**
|
|
30
|
+
* Signal version of `getExecutionCount`
|
|
31
|
+
*/
|
|
32
|
+
executionCount: Accessor<number>
|
|
33
|
+
/**
|
|
34
|
+
* Signal version of `getIsEmpty`
|
|
35
|
+
*/
|
|
36
|
+
isEmpty: Accessor<boolean>
|
|
37
|
+
/**
|
|
38
|
+
* Signal version of `getIsFull`
|
|
39
|
+
*/
|
|
40
|
+
isFull: Accessor<boolean>
|
|
41
|
+
/**
|
|
42
|
+
* Signal version of `getIsIdle`
|
|
43
|
+
*/
|
|
44
|
+
isIdle: Accessor<boolean>
|
|
45
|
+
/**
|
|
46
|
+
* Signal version of `getIsRunning`
|
|
47
|
+
*/
|
|
48
|
+
isRunning: Accessor<boolean>
|
|
49
|
+
/**
|
|
50
|
+
* Signal version of `getPeek`
|
|
51
|
+
*/
|
|
52
|
+
peek: Accessor<TValue | undefined>
|
|
53
|
+
/**
|
|
54
|
+
* Signal version of `getPendingItems`
|
|
55
|
+
*/
|
|
56
|
+
pendingItems: Accessor<Array<() => Promise<TValue>>>
|
|
57
|
+
/**
|
|
58
|
+
* Signal version of `getSize`
|
|
59
|
+
*/
|
|
60
|
+
size: Accessor<number>
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A lower-level React hook that creates an `AsyncQueuer` instance for managing an async queue of items.
|
|
65
|
+
*
|
|
66
|
+
* This hook provides a flexible, state-management agnostic way to handle queued async operations.
|
|
67
|
+
* It returns a queuer instance with methods to add items, control queue execution, and monitor queue state.
|
|
68
|
+
*
|
|
69
|
+
* The queue can be configured with:
|
|
70
|
+
* - Maximum concurrent operations
|
|
71
|
+
* - Maximum queue size
|
|
72
|
+
* - Processing function for queue items
|
|
73
|
+
* - Various lifecycle callbacks
|
|
74
|
+
*
|
|
75
|
+
* The hook returns an object containing methods to:
|
|
76
|
+
* - Add/remove items from the queue
|
|
77
|
+
* - Start/stop queue processing
|
|
78
|
+
* - Get queue status and items
|
|
79
|
+
* - Register event handlers
|
|
80
|
+
* - Control execution throttling
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* // Basic async queuer for API requests
|
|
85
|
+
* const asyncQueuer = createAsyncQueuer({
|
|
86
|
+
* initialItems: [],
|
|
87
|
+
* concurrency: 2,
|
|
88
|
+
* maxSize: 100,
|
|
89
|
+
* started: false,
|
|
90
|
+
* });
|
|
91
|
+
*
|
|
92
|
+
* // Add items to queue
|
|
93
|
+
* asyncQueuer.addItem(newItem);
|
|
94
|
+
*
|
|
95
|
+
* // Start processing
|
|
96
|
+
* asyncQueuer.start();
|
|
97
|
+
*
|
|
98
|
+
* // Handle results
|
|
99
|
+
* asyncQueuer.onSuccess((result) => {
|
|
100
|
+
* console.log('Item processed:', result);
|
|
101
|
+
* });
|
|
102
|
+
*
|
|
103
|
+
* asyncQueuer.onError((error) => {
|
|
104
|
+
* console.error('Processing failed:', error);
|
|
105
|
+
* });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export function createAsyncQueuer<TValue>(
|
|
109
|
+
initialOptions: AsyncQueuerOptions<TValue> = {},
|
|
110
|
+
): SolidAsyncQueuer<TValue> {
|
|
111
|
+
const asyncQueuer = new AsyncQueuer<TValue>(initialOptions)
|
|
112
|
+
|
|
113
|
+
const [executionCount, setExecutionCount] = createSignal(
|
|
114
|
+
asyncQueuer.getExecutionCount(),
|
|
115
|
+
)
|
|
116
|
+
const [rejectionCount, setRejectionCount] = createSignal(
|
|
117
|
+
asyncQueuer.getRejectionCount(),
|
|
118
|
+
)
|
|
119
|
+
const [isEmpty, setIsEmpty] = createSignal(asyncQueuer.getIsEmpty())
|
|
120
|
+
const [isFull, setIsFull] = createSignal(asyncQueuer.getIsFull())
|
|
121
|
+
const [isIdle, setIsIdle] = createSignal(asyncQueuer.getIsIdle())
|
|
122
|
+
const [isRunning, setIsRunning] = createSignal(asyncQueuer.getIsRunning())
|
|
123
|
+
const [allItems, setAllItems] = createSignal<Array<() => Promise<TValue>>>(
|
|
124
|
+
asyncQueuer.getAllItems(),
|
|
125
|
+
)
|
|
126
|
+
const [activeItems, setActiveItems] = createSignal<
|
|
127
|
+
Array<() => Promise<TValue>>
|
|
128
|
+
>(asyncQueuer.getActiveItems())
|
|
129
|
+
const [pendingItems, setPendingItems] = createSignal<
|
|
130
|
+
Array<() => Promise<TValue>>
|
|
131
|
+
>(asyncQueuer.getPendingItems())
|
|
132
|
+
const [peek, setPeek] = createSignal<(() => Promise<TValue>) | undefined>(
|
|
133
|
+
asyncQueuer.getPeek(),
|
|
134
|
+
)
|
|
135
|
+
const [size, setSize] = createSignal(asyncQueuer.getSize())
|
|
136
|
+
|
|
137
|
+
asyncQueuer.setOptions({
|
|
138
|
+
onItemsChange: (queuer) => {
|
|
139
|
+
setExecutionCount(queuer.getExecutionCount())
|
|
140
|
+
setIsEmpty(queuer.getIsEmpty())
|
|
141
|
+
setIsFull(queuer.getIsFull())
|
|
142
|
+
setIsIdle(queuer.getIsIdle())
|
|
143
|
+
setAllItems(queuer.getAllItems())
|
|
144
|
+
setActiveItems(queuer.getActiveItems())
|
|
145
|
+
setPendingItems(queuer.getPendingItems())
|
|
146
|
+
setPeek(() => queuer.getPeek())
|
|
147
|
+
setSize(queuer.getSize())
|
|
148
|
+
initialOptions.onItemsChange?.(queuer)
|
|
149
|
+
},
|
|
150
|
+
onIsRunningChange: (queuer) => {
|
|
151
|
+
setIsRunning(queuer.getIsRunning())
|
|
152
|
+
setIsIdle(queuer.getIsIdle())
|
|
153
|
+
initialOptions.onIsRunningChange?.(queuer)
|
|
154
|
+
},
|
|
155
|
+
onReject: (item, queuer) => {
|
|
156
|
+
setRejectionCount(queuer.getRejectionCount())
|
|
157
|
+
initialOptions.onReject?.(item, queuer)
|
|
158
|
+
},
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
return {
|
|
162
|
+
...bindInstanceMethods(asyncQueuer),
|
|
163
|
+
activeItems,
|
|
164
|
+
executionCount,
|
|
165
|
+
isEmpty,
|
|
166
|
+
isFull,
|
|
167
|
+
isIdle,
|
|
168
|
+
isRunning,
|
|
169
|
+
allItems,
|
|
170
|
+
peek,
|
|
171
|
+
pendingItems,
|
|
172
|
+
rejectionCount,
|
|
173
|
+
size,
|
|
174
|
+
}
|
|
175
|
+
}
|