@tanstack/pacer 0.22.0 → 0.23.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/README.md +4 -4
- package/dist/async-batcher.d.ts +11 -13
- package/dist/async-batcher.js +185 -131
- package/dist/async-debouncer.d.ts +6 -8
- package/dist/async-debouncer.js +186 -142
- package/dist/async-queuer.d.ts +11 -13
- package/dist/async-queuer.js +383 -290
- package/dist/async-rate-limiter.d.ts +6 -8
- package/dist/async-rate-limiter.js +197 -143
- package/dist/async-retryer.d.ts +6 -8
- package/dist/async-retryer.js +209 -179
- package/dist/async-throttler.d.ts +6 -8
- package/dist/async-throttler.js +214 -157
- package/dist/batcher.d.ts +5 -7
- package/dist/batcher.js +107 -87
- package/dist/debouncer.d.ts +6 -8
- package/dist/debouncer.js +99 -86
- package/dist/event-client.d.ts +8 -10
- package/dist/event-client.js +1 -2
- package/dist/queuer.d.ts +7 -9
- package/dist/queuer.js +277 -212
- package/dist/rate-limiter.d.ts +6 -8
- package/dist/rate-limiter.js +127 -109
- package/dist/throttler.d.ts +6 -8
- package/dist/throttler.js +127 -90
- package/dist/types.d.ts +4 -6
- package/dist/utils.d.ts +3 -5
- package/dist/utils.js +1 -2
- package/package.json +21 -68
- package/dist/async-batcher.cjs +0 -337
- package/dist/async-batcher.cjs.map +0 -1
- package/dist/async-batcher.d.cts +0 -343
- package/dist/async-batcher.js.map +0 -1
- package/dist/async-debouncer.cjs +0 -327
- package/dist/async-debouncer.cjs.map +0 -1
- package/dist/async-debouncer.d.cts +0 -299
- package/dist/async-debouncer.js.map +0 -1
- package/dist/async-queuer.cjs +0 -516
- package/dist/async-queuer.cjs.map +0 -1
- package/dist/async-queuer.d.cts +0 -440
- package/dist/async-queuer.js.map +0 -1
- package/dist/async-rate-limiter.cjs +0 -370
- package/dist/async-rate-limiter.cjs.map +0 -1
- package/dist/async-rate-limiter.d.cts +0 -356
- package/dist/async-rate-limiter.js.map +0 -1
- package/dist/async-retryer.cjs +0 -365
- package/dist/async-retryer.cjs.map +0 -1
- package/dist/async-retryer.d.cts +0 -321
- package/dist/async-retryer.js.map +0 -1
- package/dist/async-throttler.cjs +0 -344
- package/dist/async-throttler.cjs.map +0 -1
- package/dist/async-throttler.d.cts +0 -319
- package/dist/async-throttler.js.map +0 -1
- package/dist/batcher.cjs +0 -200
- package/dist/batcher.cjs.map +0 -1
- package/dist/batcher.d.cts +0 -179
- package/dist/batcher.js.map +0 -1
- package/dist/debouncer.cjs +0 -203
- package/dist/debouncer.cjs.map +0 -1
- package/dist/debouncer.d.cts +0 -166
- package/dist/debouncer.js.map +0 -1
- package/dist/event-client.cjs +0 -64
- package/dist/event-client.cjs.map +0 -1
- package/dist/event-client.d.cts +0 -65
- package/dist/event-client.js.map +0 -1
- package/dist/index.cjs +0 -52
- package/dist/index.d.cts +0 -15
- package/dist/queuer.cjs +0 -406
- package/dist/queuer.cjs.map +0 -1
- package/dist/queuer.d.cts +0 -345
- package/dist/queuer.js.map +0 -1
- package/dist/rate-limiter.cjs +0 -263
- package/dist/rate-limiter.cjs.map +0 -1
- package/dist/rate-limiter.d.cts +0 -214
- package/dist/rate-limiter.js.map +0 -1
- package/dist/throttler.cjs +0 -215
- package/dist/throttler.cjs.map +0 -1
- package/dist/throttler.d.cts +0 -206
- package/dist/throttler.js.map +0 -1
- package/dist/types.cjs +0 -0
- package/dist/types.d.cts +0 -13
- package/dist/utils.cjs +0 -13
- package/dist/utils.cjs.map +0 -1
- package/dist/utils.d.cts +0 -7
- package/dist/utils.js.map +0 -1
- package/src/async-batcher.ts +0 -594
- package/src/async-debouncer.ts +0 -566
- package/src/async-queuer.ts +0 -988
- package/src/async-rate-limiter.ts +0 -648
- package/src/async-retryer.ts +0 -673
- package/src/async-throttler.ts +0 -634
- package/src/batcher.ts +0 -329
- package/src/debouncer.ts +0 -334
- package/src/event-client.ts +0 -129
- package/src/index.ts +0 -24
- package/src/queuer.ts +0 -751
- package/src/rate-limiter.ts +0 -429
- package/src/throttler.ts +0 -380
- package/src/types.ts +0 -12
- package/src/utils.ts +0 -12
package/README.md
CHANGED
|
@@ -103,10 +103,10 @@ A lightweight timing and scheduling library for debouncing, throttling, rate lim
|
|
|
103
103
|
> [!NOTE]
|
|
104
104
|
> You may know **TanStack Pacer** by our adapter names, too!
|
|
105
105
|
>
|
|
106
|
-
> - [**React Pacer**](https://tanstack.com/pacer/latest/docs/framework/react
|
|
107
|
-
> - [**Preact Pacer**](https://tanstack.com/pacer/latest/docs/framework/preact
|
|
108
|
-
> - [**Solid Pacer**](https://tanstack.com/pacer/latest/docs/framework/solid
|
|
109
|
-
> - [**Angular Pacer**](https://tanstack.com/pacer/latest/docs/framework/angular
|
|
106
|
+
> - [**React Pacer**](https://tanstack.com/pacer/latest/docs/framework/react)
|
|
107
|
+
> - [**Preact Pacer**](https://tanstack.com/pacer/latest/docs/framework/preact)
|
|
108
|
+
> - [**Solid Pacer**](https://tanstack.com/pacer/latest/docs/framework/solid)
|
|
109
|
+
> - [**Angular Pacer**](https://tanstack.com/pacer/latest/docs/framework/angular)
|
|
110
110
|
> - Svelte Pacer - needs a contributor!
|
|
111
111
|
> - Vue Pacer - needs a contributor!
|
|
112
112
|
|
package/dist/async-batcher.d.ts
CHANGED
|
@@ -2,15 +2,15 @@ import { OptionalKeys } from "./types.js";
|
|
|
2
2
|
import { AsyncRetryer, AsyncRetryerOptions } from "./async-retryer.js";
|
|
3
3
|
import { Store } from "@tanstack/store";
|
|
4
4
|
//#region src/async-batcher.d.ts
|
|
5
|
-
interface AsyncBatcherState<TValue> {
|
|
5
|
+
export interface AsyncBatcherState<TValue> {
|
|
6
6
|
/**
|
|
7
7
|
* Number of batch executions that have resulted in errors
|
|
8
8
|
*/
|
|
9
9
|
errorCount: number;
|
|
10
10
|
/**
|
|
11
|
-
* Number of batch executions that have been
|
|
11
|
+
* Number of batch executions that have been started
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
executionCount: number;
|
|
14
14
|
/**
|
|
15
15
|
* Array of items that failed during batch processing
|
|
16
16
|
*/
|
|
@@ -63,7 +63,7 @@ interface AsyncBatcherState<TValue> {
|
|
|
63
63
|
/**
|
|
64
64
|
* Options for configuring an AsyncBatcher instance
|
|
65
65
|
*/
|
|
66
|
-
interface AsyncBatcherOptions<TValue> {
|
|
66
|
+
export interface AsyncBatcherOptions<TValue> {
|
|
67
67
|
/**
|
|
68
68
|
* Options for configuring the underlying async retryer
|
|
69
69
|
*/
|
|
@@ -128,7 +128,7 @@ interface AsyncBatcherOptions<TValue> {
|
|
|
128
128
|
* Utility function for sharing common `AsyncBatcherOptions` options between different `AsyncBatcher` instances.
|
|
129
129
|
*
|
|
130
130
|
*/
|
|
131
|
-
declare function asyncBatcherOptions<TValue = any, TOptions extends Partial<AsyncBatcherOptions<TValue>> = Partial<AsyncBatcherOptions<TValue>>>(options: TOptions): TOptions;
|
|
131
|
+
export declare function asyncBatcherOptions<TValue = any, TOptions extends Partial<AsyncBatcherOptions<TValue>> = Partial<AsyncBatcherOptions<TValue>>>(options: TOptions): TOptions;
|
|
132
132
|
type AsyncBatcherOptionsWithOptionalCallbacks<TValue> = OptionalKeys<Required<AsyncBatcherOptions<TValue>>, 'initialState' | 'onError' | 'onItemsChange' | 'onSettled' | 'onSuccess' | 'key'>;
|
|
133
133
|
/**
|
|
134
134
|
* A class that collects items and processes them in batches asynchronously.
|
|
@@ -197,7 +197,7 @@ type AsyncBatcherOptionsWithOptionalCallbacks<TValue> = OptionalKeys<Required<As
|
|
|
197
197
|
* // batcher.execute() // manually trigger a batch
|
|
198
198
|
* ```
|
|
199
199
|
*/
|
|
200
|
-
declare class AsyncBatcher<TValue> {
|
|
200
|
+
export declare class AsyncBatcher<TValue> {
|
|
201
201
|
#private;
|
|
202
202
|
fn: (items: Array<TValue>) => Promise<any>;
|
|
203
203
|
readonly store: Store<Readonly<AsyncBatcherState<TValue>>>;
|
|
@@ -233,10 +233,10 @@ declare class AsyncBatcher<TValue> {
|
|
|
233
233
|
clear: () => void;
|
|
234
234
|
/**
|
|
235
235
|
* Returns the AbortSignal for a specific execution.
|
|
236
|
-
* If no
|
|
236
|
+
* If no executionCount is provided, returns the signal for the most recent execution.
|
|
237
237
|
* Returns null if no execution is found or not currently executing.
|
|
238
238
|
*
|
|
239
|
-
* @param
|
|
239
|
+
* @param executionCount - Optional specific execution to get signal for
|
|
240
240
|
* @example
|
|
241
241
|
* ```typescript
|
|
242
242
|
* const batcher = new AsyncBatcher(
|
|
@@ -255,7 +255,7 @@ declare class AsyncBatcher<TValue> {
|
|
|
255
255
|
* )
|
|
256
256
|
* ```
|
|
257
257
|
*/
|
|
258
|
-
getAbortSignal: (
|
|
258
|
+
getAbortSignal: (executionCount?: number) => AbortSignal | null;
|
|
259
259
|
/**
|
|
260
260
|
* Aborts all ongoing executions with the internal abort controllers.
|
|
261
261
|
* Does NOT cancel any pending execution that have not started yet.
|
|
@@ -337,7 +337,5 @@ declare class AsyncBatcher<TValue> {
|
|
|
337
337
|
* batchItems(3); // Triggers batch processing
|
|
338
338
|
* ```
|
|
339
339
|
*/
|
|
340
|
-
declare function asyncBatch<TValue>(fn: (items: Array<TValue>) => Promise<any>, options: AsyncBatcherOptions<TValue>): (item: TValue) => Promise<any>;
|
|
341
|
-
//#endregion
|
|
342
|
-
export { AsyncBatcher, AsyncBatcherOptions, AsyncBatcherState, asyncBatch, asyncBatcherOptions };
|
|
343
|
-
//# sourceMappingURL=async-batcher.d.ts.map
|
|
340
|
+
export declare function asyncBatch<TValue>(fn: (items: Array<TValue>) => Promise<any>, options: AsyncBatcherOptions<TValue>): (item: TValue) => Promise<any>;
|
|
341
|
+
//#endregion
|
package/dist/async-batcher.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Store } from "@tanstack/store";
|
|
|
7
7
|
function getDefaultAsyncBatcherState() {
|
|
8
8
|
return {
|
|
9
9
|
errorCount: 0,
|
|
10
|
-
|
|
10
|
+
executionCount: 0,
|
|
11
11
|
failedItems: [],
|
|
12
12
|
isEmpty: true,
|
|
13
13
|
isExecuting: false,
|
|
@@ -105,132 +105,14 @@ const defaultOptions = {
|
|
|
105
105
|
* ```
|
|
106
106
|
*/
|
|
107
107
|
var AsyncBatcher = class {
|
|
108
|
-
|
|
108
|
+
fn;
|
|
109
|
+
store = new Store(getDefaultAsyncBatcherState());
|
|
110
|
+
key;
|
|
111
|
+
options;
|
|
112
|
+
asyncRetryers = /* @__PURE__ */ new Map();
|
|
113
|
+
#timeoutId = null;
|
|
109
114
|
constructor(fn, initialOptions) {
|
|
110
115
|
this.fn = fn;
|
|
111
|
-
this.store = new Store(getDefaultAsyncBatcherState());
|
|
112
|
-
this.asyncRetryers = /* @__PURE__ */ new Map();
|
|
113
|
-
this.#timeoutId = null;
|
|
114
|
-
this.setOptions = (newOptions) => {
|
|
115
|
-
this.options = {
|
|
116
|
-
...this.options,
|
|
117
|
-
...newOptions
|
|
118
|
-
};
|
|
119
|
-
};
|
|
120
|
-
this.#setState = (newState) => {
|
|
121
|
-
this.store.setState((state) => {
|
|
122
|
-
const combinedState = {
|
|
123
|
-
...state,
|
|
124
|
-
...newState
|
|
125
|
-
};
|
|
126
|
-
const { isExecuting, isPending, items } = combinedState;
|
|
127
|
-
const size = items.length;
|
|
128
|
-
const isEmpty = size === 0;
|
|
129
|
-
return {
|
|
130
|
-
...combinedState,
|
|
131
|
-
isEmpty,
|
|
132
|
-
size,
|
|
133
|
-
status: isExecuting ? "executing" : isPending ? "pending" : isEmpty ? "idle" : "populated"
|
|
134
|
-
};
|
|
135
|
-
});
|
|
136
|
-
emitChange("AsyncBatcher", this);
|
|
137
|
-
};
|
|
138
|
-
this.#getWait = () => {
|
|
139
|
-
return parseFunctionOrValue(this.options.wait, this);
|
|
140
|
-
};
|
|
141
|
-
this.addItem = async (item) => {
|
|
142
|
-
this.#setState({
|
|
143
|
-
items: [...this.store.state.items, item],
|
|
144
|
-
isPending: this.options.wait !== Infinity
|
|
145
|
-
});
|
|
146
|
-
this.options.onItemsChange?.(this);
|
|
147
|
-
if (this.store.state.items.length >= this.options.maxSize || this.options.getShouldExecute(this.store.state.items, this)) return await this.#execute();
|
|
148
|
-
else if (this.options.wait !== Infinity) {
|
|
149
|
-
this.#clearTimeout();
|
|
150
|
-
this.#timeoutId = setTimeout(() => this.#execute(), this.#getWait());
|
|
151
|
-
await new Promise((resolve) => setTimeout(resolve, this.#getWait()));
|
|
152
|
-
}
|
|
153
|
-
};
|
|
154
|
-
this.#execute = async () => {
|
|
155
|
-
if (this.store.state.items.length === 0) return;
|
|
156
|
-
const currentExecuteCount = this.store.state.executeCount + 1;
|
|
157
|
-
const batch = this.peekAllItems();
|
|
158
|
-
this.clear();
|
|
159
|
-
this.options.onItemsChange?.(this);
|
|
160
|
-
this.#setState({
|
|
161
|
-
isExecuting: true,
|
|
162
|
-
executeCount: currentExecuteCount
|
|
163
|
-
});
|
|
164
|
-
try {
|
|
165
|
-
const currentAsyncRetryer = new AsyncRetryer(this.fn, this.options.asyncRetryerOptions);
|
|
166
|
-
this.asyncRetryers.set(currentExecuteCount, currentAsyncRetryer);
|
|
167
|
-
const result = await currentAsyncRetryer.execute(batch);
|
|
168
|
-
this.#setState({
|
|
169
|
-
totalItemsProcessed: this.store.state.totalItemsProcessed + batch.length,
|
|
170
|
-
lastResult: result,
|
|
171
|
-
successCount: this.store.state.successCount + 1
|
|
172
|
-
});
|
|
173
|
-
this.options.onSuccess?.(result, batch, this);
|
|
174
|
-
return result;
|
|
175
|
-
} catch (error) {
|
|
176
|
-
this.#setState({
|
|
177
|
-
errorCount: this.store.state.errorCount + 1,
|
|
178
|
-
failedItems: [...this.store.state.failedItems, ...batch],
|
|
179
|
-
totalItemsFailed: this.store.state.totalItemsFailed + batch.length
|
|
180
|
-
});
|
|
181
|
-
this.options.onError?.(error, batch, this);
|
|
182
|
-
if (this.options.throwOnError) throw error;
|
|
183
|
-
return;
|
|
184
|
-
} finally {
|
|
185
|
-
this.asyncRetryers.delete(currentExecuteCount);
|
|
186
|
-
this.#setState({
|
|
187
|
-
isExecuting: false,
|
|
188
|
-
settleCount: this.store.state.settleCount + 1
|
|
189
|
-
});
|
|
190
|
-
this.options.onSettled?.(batch, this);
|
|
191
|
-
}
|
|
192
|
-
};
|
|
193
|
-
this.flush = async () => {
|
|
194
|
-
this.#clearTimeout();
|
|
195
|
-
return await this.#execute();
|
|
196
|
-
};
|
|
197
|
-
this.peekAllItems = () => {
|
|
198
|
-
return [...this.store.state.items];
|
|
199
|
-
};
|
|
200
|
-
this.peekFailedItems = () => {
|
|
201
|
-
return [...this.store.state.failedItems];
|
|
202
|
-
};
|
|
203
|
-
this.#clearTimeout = () => {
|
|
204
|
-
if (this.#timeoutId) {
|
|
205
|
-
clearTimeout(this.#timeoutId);
|
|
206
|
-
this.#timeoutId = null;
|
|
207
|
-
}
|
|
208
|
-
};
|
|
209
|
-
this.clear = () => {
|
|
210
|
-
this.#setState({
|
|
211
|
-
items: [],
|
|
212
|
-
failedItems: [],
|
|
213
|
-
isPending: false
|
|
214
|
-
});
|
|
215
|
-
};
|
|
216
|
-
this.getAbortSignal = (executeCount) => {
|
|
217
|
-
const count = executeCount ?? this.store.state.executeCount;
|
|
218
|
-
return this.asyncRetryers.get(count)?.getAbortSignal() ?? null;
|
|
219
|
-
};
|
|
220
|
-
this.abort = () => {
|
|
221
|
-
this.asyncRetryers.forEach((retryer) => retryer.abort());
|
|
222
|
-
this.asyncRetryers.clear();
|
|
223
|
-
this.#setState({ isExecuting: false });
|
|
224
|
-
};
|
|
225
|
-
this.cancel = () => {
|
|
226
|
-
this.#clearTimeout();
|
|
227
|
-
this.#setState({ isPending: false });
|
|
228
|
-
};
|
|
229
|
-
this.reset = () => {
|
|
230
|
-
this.#setState(getDefaultAsyncBatcherState());
|
|
231
|
-
this.options.onItemsChange?.(this);
|
|
232
|
-
this.asyncRetryers.forEach((retryer) => retryer.reset());
|
|
233
|
-
};
|
|
234
116
|
this.key = initialOptions.key;
|
|
235
117
|
this.options = {
|
|
236
118
|
...defaultOptions,
|
|
@@ -244,8 +126,57 @@ var AsyncBatcher = class {
|
|
|
244
126
|
this.setOptions(event.payload.options);
|
|
245
127
|
});
|
|
246
128
|
}
|
|
247
|
-
|
|
248
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Updates the async batcher options
|
|
131
|
+
*/
|
|
132
|
+
setOptions = (newOptions) => {
|
|
133
|
+
this.options = {
|
|
134
|
+
...this.options,
|
|
135
|
+
...newOptions
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
#setState = (newState) => {
|
|
139
|
+
this.store.setState((state) => {
|
|
140
|
+
const combinedState = {
|
|
141
|
+
...state,
|
|
142
|
+
...newState
|
|
143
|
+
};
|
|
144
|
+
const { isExecuting, isPending, items } = combinedState;
|
|
145
|
+
const size = items.length;
|
|
146
|
+
const isEmpty = size === 0;
|
|
147
|
+
return {
|
|
148
|
+
...combinedState,
|
|
149
|
+
isEmpty,
|
|
150
|
+
size,
|
|
151
|
+
status: isExecuting ? "executing" : isPending ? "pending" : isEmpty ? "idle" : "populated"
|
|
152
|
+
};
|
|
153
|
+
});
|
|
154
|
+
emitChange("AsyncBatcher", this);
|
|
155
|
+
};
|
|
156
|
+
#getWait = () => {
|
|
157
|
+
return parseFunctionOrValue(this.options.wait, this);
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Adds an item to the async batcher
|
|
161
|
+
* If the batch size is reached, timeout occurs, or shouldProcess returns true, the batch will be processed
|
|
162
|
+
*
|
|
163
|
+
* @returns The result from the batch function, or undefined if an error occurred and was handled by onError
|
|
164
|
+
*
|
|
165
|
+
* @throws The error from the batch function if no onError handler is configured or throwOnError is true
|
|
166
|
+
*/
|
|
167
|
+
addItem = async (item) => {
|
|
168
|
+
this.#setState({
|
|
169
|
+
items: [...this.store.state.items, item],
|
|
170
|
+
isPending: this.options.wait !== Infinity
|
|
171
|
+
});
|
|
172
|
+
this.options.onItemsChange?.(this);
|
|
173
|
+
if (this.store.state.items.length >= this.options.maxSize || this.options.getShouldExecute(this.store.state.items, this)) return await this.#execute();
|
|
174
|
+
else if (this.options.wait !== Infinity) {
|
|
175
|
+
this.#clearTimeout();
|
|
176
|
+
this.#timeoutId = setTimeout(() => this.#execute(), this.#getWait());
|
|
177
|
+
await new Promise((resolve) => setTimeout(resolve, this.#getWait()));
|
|
178
|
+
}
|
|
179
|
+
};
|
|
249
180
|
/**
|
|
250
181
|
* Processes the current batch of items asynchronously.
|
|
251
182
|
* This method will automatically be triggered if the batcher is running and any of these conditions are met:
|
|
@@ -258,8 +189,132 @@ var AsyncBatcher = class {
|
|
|
258
189
|
* @returns A promise that resolves with the result of the batch function, or undefined if an error occurred and was handled by onError
|
|
259
190
|
* @throws The error from the batch function if no onError handler is configured or throwOnError is true
|
|
260
191
|
*/
|
|
261
|
-
#execute
|
|
262
|
-
|
|
192
|
+
#execute = async () => {
|
|
193
|
+
if (this.store.state.items.length === 0) return;
|
|
194
|
+
const currentExecutionCount = this.store.state.executionCount + 1;
|
|
195
|
+
const batch = this.peekAllItems();
|
|
196
|
+
this.clear();
|
|
197
|
+
this.options.onItemsChange?.(this);
|
|
198
|
+
this.#setState({
|
|
199
|
+
isExecuting: true,
|
|
200
|
+
executionCount: currentExecutionCount
|
|
201
|
+
});
|
|
202
|
+
try {
|
|
203
|
+
const currentAsyncRetryer = new AsyncRetryer(this.fn, this.options.asyncRetryerOptions);
|
|
204
|
+
this.asyncRetryers.set(currentExecutionCount, currentAsyncRetryer);
|
|
205
|
+
const result = await currentAsyncRetryer.execute(batch);
|
|
206
|
+
this.#setState({
|
|
207
|
+
totalItemsProcessed: this.store.state.totalItemsProcessed + batch.length,
|
|
208
|
+
lastResult: result,
|
|
209
|
+
successCount: this.store.state.successCount + 1
|
|
210
|
+
});
|
|
211
|
+
this.options.onSuccess?.(result, batch, this);
|
|
212
|
+
return result;
|
|
213
|
+
} catch (error) {
|
|
214
|
+
this.#setState({
|
|
215
|
+
errorCount: this.store.state.errorCount + 1,
|
|
216
|
+
failedItems: [...this.store.state.failedItems, ...batch],
|
|
217
|
+
totalItemsFailed: this.store.state.totalItemsFailed + batch.length
|
|
218
|
+
});
|
|
219
|
+
this.options.onError?.(error, batch, this);
|
|
220
|
+
if (this.options.throwOnError) throw error;
|
|
221
|
+
return;
|
|
222
|
+
} finally {
|
|
223
|
+
this.asyncRetryers.delete(currentExecutionCount);
|
|
224
|
+
this.#setState({
|
|
225
|
+
isExecuting: false,
|
|
226
|
+
settleCount: this.store.state.settleCount + 1
|
|
227
|
+
});
|
|
228
|
+
this.options.onSettled?.(batch, this);
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Processes the current batch of items immediately
|
|
233
|
+
*/
|
|
234
|
+
flush = async () => {
|
|
235
|
+
this.#clearTimeout();
|
|
236
|
+
return await this.#execute();
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Returns a copy of all items in the async batcher
|
|
240
|
+
*/
|
|
241
|
+
peekAllItems = () => {
|
|
242
|
+
return [...this.store.state.items];
|
|
243
|
+
};
|
|
244
|
+
peekFailedItems = () => {
|
|
245
|
+
return [...this.store.state.failedItems];
|
|
246
|
+
};
|
|
247
|
+
#clearTimeout = () => {
|
|
248
|
+
if (this.#timeoutId) {
|
|
249
|
+
clearTimeout(this.#timeoutId);
|
|
250
|
+
this.#timeoutId = null;
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Removes all items from the async batcher
|
|
255
|
+
*/
|
|
256
|
+
clear = () => {
|
|
257
|
+
this.#setState({
|
|
258
|
+
items: [],
|
|
259
|
+
failedItems: [],
|
|
260
|
+
isPending: false
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Returns the AbortSignal for a specific execution.
|
|
265
|
+
* If no executionCount is provided, returns the signal for the most recent execution.
|
|
266
|
+
* Returns null if no execution is found or not currently executing.
|
|
267
|
+
*
|
|
268
|
+
* @param executionCount - Optional specific execution to get signal for
|
|
269
|
+
* @example
|
|
270
|
+
* ```typescript
|
|
271
|
+
* const batcher = new AsyncBatcher(
|
|
272
|
+
* async (items: string[]) => {
|
|
273
|
+
* const signal = batcher.getAbortSignal()
|
|
274
|
+
* if (signal) {
|
|
275
|
+
* const response = await fetch('/api/batch', {
|
|
276
|
+
* method: 'POST',
|
|
277
|
+
* body: JSON.stringify(items),
|
|
278
|
+
* signal
|
|
279
|
+
* })
|
|
280
|
+
* return response.json()
|
|
281
|
+
* }
|
|
282
|
+
* },
|
|
283
|
+
* { maxSize: 10, wait: 100 }
|
|
284
|
+
* )
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
getAbortSignal = (executionCount) => {
|
|
288
|
+
const count = executionCount ?? this.store.state.executionCount;
|
|
289
|
+
return this.asyncRetryers.get(count)?.getAbortSignal() ?? null;
|
|
290
|
+
};
|
|
291
|
+
/**
|
|
292
|
+
* Aborts all ongoing executions with the internal abort controllers.
|
|
293
|
+
* Does NOT cancel any pending execution that have not started yet.
|
|
294
|
+
* Does NOT clear out the items.
|
|
295
|
+
*/
|
|
296
|
+
abort = () => {
|
|
297
|
+
this.asyncRetryers.forEach((retryer) => retryer.abort());
|
|
298
|
+
this.asyncRetryers.clear();
|
|
299
|
+
this.#setState({ isExecuting: false });
|
|
300
|
+
};
|
|
301
|
+
/**
|
|
302
|
+
* Cancels any pending execution that have not started yet.
|
|
303
|
+
* Does NOT abort any execution already in progress.
|
|
304
|
+
* Does NOT clear out the items.
|
|
305
|
+
*/
|
|
306
|
+
cancel = () => {
|
|
307
|
+
this.#clearTimeout();
|
|
308
|
+
this.#setState({ isPending: false });
|
|
309
|
+
};
|
|
310
|
+
/**
|
|
311
|
+
* Resets the async batcher state to its default values
|
|
312
|
+
*/
|
|
313
|
+
reset = () => {
|
|
314
|
+
this.#setState(getDefaultAsyncBatcherState());
|
|
315
|
+
this.options.onItemsChange?.(this);
|
|
316
|
+
this.asyncRetryers.forEach((retryer) => retryer.reset());
|
|
317
|
+
};
|
|
263
318
|
};
|
|
264
319
|
/**
|
|
265
320
|
* Creates an async batcher that processes items in batches.
|
|
@@ -330,5 +385,4 @@ function asyncBatch(fn, options) {
|
|
|
330
385
|
}
|
|
331
386
|
|
|
332
387
|
//#endregion
|
|
333
|
-
export { AsyncBatcher, asyncBatch, asyncBatcherOptions };
|
|
334
|
-
//# sourceMappingURL=async-batcher.js.map
|
|
388
|
+
export { AsyncBatcher, asyncBatch, asyncBatcherOptions };
|
|
@@ -2,7 +2,7 @@ import { AnyAsyncFunction } from "./types.js";
|
|
|
2
2
|
import { AsyncRetryer, AsyncRetryerOptions } from "./async-retryer.js";
|
|
3
3
|
import { Store } from "@tanstack/store";
|
|
4
4
|
//#region src/async-debouncer.d.ts
|
|
5
|
-
interface AsyncDebouncerState<TFn extends AnyAsyncFunction> {
|
|
5
|
+
export interface AsyncDebouncerState<TFn extends AnyAsyncFunction> {
|
|
6
6
|
/**
|
|
7
7
|
* Whether the debouncer can execute on the leading edge of the timeout
|
|
8
8
|
*/
|
|
@@ -47,7 +47,7 @@ interface AsyncDebouncerState<TFn extends AnyAsyncFunction> {
|
|
|
47
47
|
/**
|
|
48
48
|
* Options for configuring an async debounced function
|
|
49
49
|
*/
|
|
50
|
-
interface AsyncDebouncerOptions<TFn extends AnyAsyncFunction> {
|
|
50
|
+
export interface AsyncDebouncerOptions<TFn extends AnyAsyncFunction> {
|
|
51
51
|
/**
|
|
52
52
|
* Options for configuring the underlying async retryer
|
|
53
53
|
*/
|
|
@@ -107,7 +107,7 @@ interface AsyncDebouncerOptions<TFn extends AnyAsyncFunction> {
|
|
|
107
107
|
/**
|
|
108
108
|
* Utility function for sharing common `AsyncDebouncerOptions` options between different `AsyncDebouncer` instances.
|
|
109
109
|
*/
|
|
110
|
-
declare function asyncDebouncerOptions<TFn extends AnyAsyncFunction = AnyAsyncFunction, TOptions extends Partial<AsyncDebouncerOptions<TFn>> = Partial<AsyncDebouncerOptions<TFn>>>(options: TOptions): TOptions;
|
|
110
|
+
export declare function asyncDebouncerOptions<TFn extends AnyAsyncFunction = AnyAsyncFunction, TOptions extends Partial<AsyncDebouncerOptions<TFn>> = Partial<AsyncDebouncerOptions<TFn>>>(options: TOptions): TOptions;
|
|
111
111
|
/**
|
|
112
112
|
* A class that creates an async debounced function.
|
|
113
113
|
*
|
|
@@ -162,7 +162,7 @@ declare function asyncDebouncerOptions<TFn extends AnyAsyncFunction = AnyAsyncFu
|
|
|
162
162
|
* const results = await asyncDebouncer.maybeExecute(inputElement.value);
|
|
163
163
|
* ```
|
|
164
164
|
*/
|
|
165
|
-
declare class AsyncDebouncer<TFn extends AnyAsyncFunction> {
|
|
165
|
+
export declare class AsyncDebouncer<TFn extends AnyAsyncFunction> {
|
|
166
166
|
#private;
|
|
167
167
|
fn: TFn;
|
|
168
168
|
readonly store: Store<Readonly<AsyncDebouncerState<TFn>>>;
|
|
@@ -293,7 +293,5 @@ declare class AsyncDebouncer<TFn extends AnyAsyncFunction> {
|
|
|
293
293
|
* const result = await debounced("third");
|
|
294
294
|
* ```
|
|
295
295
|
*/
|
|
296
|
-
declare function asyncDebounce<TFn extends AnyAsyncFunction>(fn: TFn, initialOptions: AsyncDebouncerOptions<TFn>): (...args: Parameters<TFn>) => Promise<Awaited<ReturnType<TFn>> | undefined>;
|
|
297
|
-
//#endregion
|
|
298
|
-
export { AsyncDebouncer, AsyncDebouncerOptions, AsyncDebouncerState, asyncDebounce, asyncDebouncerOptions };
|
|
299
|
-
//# sourceMappingURL=async-debouncer.d.ts.map
|
|
296
|
+
export declare function asyncDebounce<TFn extends AnyAsyncFunction>(fn: TFn, initialOptions: AsyncDebouncerOptions<TFn>): (...args: Parameters<TFn>) => Promise<Awaited<ReturnType<TFn>> | undefined>;
|
|
297
|
+
//#endregion
|