@handy-common-utils/promise-utils 1.5.0 → 1.7.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 CHANGED
@@ -3,16 +3,19 @@
3
3
  These Promise-related utilities boast 100% test coverage, ensuring robust reliability.
4
4
  The package, free of external dependencies, offers essential functions such as:
5
5
 
6
- - `repeat`: Executes an operation repeatedly, very useful to collect all results through pagination.
7
- - `withRetry`: Retries an operation until a specified condition is met.
8
- - `withConcurrency`: Executes multiple operations with specified level of concurrency, and abort remaining operations when an error happens.
9
- - `inParallel`: Executes multiple operations with specified level of concurrency, all operations are guaranteed to be executed regardless of any possible error.
6
+ - `repeat`: Executes an operation repeatedly; useful for collecting paged results.
7
+ - `withRetry`: Retries an operation with configurable backoff and retry predicate.
8
+ - `withConcurrency`: Runs jobs in parallel with a concurrency limit and aborts remaining jobs on the first error.
9
+ - `inParallel`: Runs jobs in parallel with a concurrency limit and returns all results and errors (does not abort on any error by default).
10
10
  - `delayedResolve`: Creates a Promise that resolves after a specified delay.
11
11
  - `delayedReject`: Creates a Promise that rejects after a specified delay.
12
- - `timeoutResolve`: Applies a timeout to a Promise and resolves with a specified result if the timeout occurs.
13
- - `timeoutReject`: Applies a timeout to a Promise and rejects with a specified error/reason if the timeout occurs.
14
- - `promiseState`: Retrieves the state of a Promise.
15
- - `synchronized`: Provides mutual exclusion for concurrent operations using a lock mechanism, similar to `synchronized` in Java.
12
+ - `cancellableDelayedResolve`: Like `delayedResolve` but returns `{ stop(), promise }` to allow cancelling before the timer fires.
13
+ - `cancellableDelayedReject`: Like `delayedReject` but returns `{ stop(), promise }` to allow cancelling before the timer fires.
14
+ - `timeoutResolve`: Applies a timeout to a Promise and resolves with a fallback value if the timeout occurs.
15
+ - `timeoutReject`: Applies a timeout to a Promise and rejects with a fallback reason if the timeout occurs.
16
+ - `promiseState`: Retrieves the state of a Promise (Pending/Fulfilled/Rejected).
17
+ - `synchronized` / `synchronised`: Provides mutual exclusion (lock) semantics for async operations.
18
+ - `runPeriodically`: Runs an operation periodically with configurable intervals and stopping conditions.
16
19
 
17
20
  [![Version](https://img.shields.io/npm/v/@handy-common-utils/promise-utils.svg)](https://npmjs.org/package/@handy-common-utils/promise-utils)
18
21
  [![Downloads/week](https://img.shields.io/npm/dw/@handy-common-utils/promise-utils.svg)](https://npmjs.org/package/@handy-common-utils/promise-utils)
@@ -27,63 +30,77 @@ First add it as a dependency:
27
30
  npm install @handy-common-utils/promise-utils
28
31
  ```
29
32
 
30
- Then you can use it in the code:
33
+ Then you can use it in the code. Below are minimal examples; full short snippets are grouped in the "Examples" section further down.
31
34
 
32
35
  ```javascript
33
36
  import { PromiseUtils } from '@handy-common-utils/promise-utils';
34
37
 
35
- // delayedResolve(...), delayedReject(...), promiseState(...)
36
- const p1 = PromiseUtils.delayedResolve(50, 1);
37
- const p2 = PromiseUtils.delayedReject(50, 2);
38
- await expect(PromiseUtils.promiseState(p1)).eventually.eq(PromiseState.Pending);
39
- await expect(PromiseUtils.promiseState(p2)).eventually.eq(PromiseState.Pending);
40
- await PromiseUtils.delayedResolve(80);
41
- await expect(PromiseUtils.promiseState(p1)).eventually.eq(PromiseState.Fulfilled);
42
- await expect(PromiseUtils.promiseState(p2)).eventually.eq(PromiseState.Rejected);
43
-
44
- // timeoutReject(...)
45
- const p = PromiseUtils.timeoutReject(PromiseUtils.delayedReject(80, '1'), 10, '2');
46
- await expect(p).to.be.rejectedWith('2');
47
-
48
- // repeat(...)
49
- async repeatFetchingItemsByPosition<T>(
50
- fetchItemsByPosition: (parameter: { position?: string }) => Promise<{ position?: string; items?: Array<T> }>,
51
- ) {
52
- return PromiseUtils.repeat(
53
- fetchItemsByPosition,
54
- response => response.position ? { position: response.position } : null,
55
- (collection, response) => response.items ? collection.concat(response.items) : collection,
56
- [] as Array<T>,
57
- );
58
- }
38
+ // basic usage (short):
39
+ await PromiseUtils.delayedResolve(50, 'ok');
40
+ await PromiseUtils.timeoutReject(PromiseUtils.delayedReject(80, '1'), 10, '2');
41
+
42
+ // See the Examples section below for more grouped snippets (Timers, Concurrency, Scheduling).
59
43
  ```
60
44
 
61
- You can either import and use the [PromiseUtils class](#classespromiseutilsmd) as shown above,
62
- or you can import its re-exported functions directly like below:
45
+ You can either import and use the [PromiseUtils class](#classespromiseutilsmd) as shown above, or import only the helpers you need. For example:
63
46
 
64
47
  ```javascript
65
- import { withRetry, inParallel, FIBONACCI_SEQUENCE, EXPONENTIAL_SEQUENCE } from '@handy-common-utils/promise-utils';
48
+ import { withRetry, delayedResolve, cancellableDelayedReject, withConcurrency, inParallel, runPeriodically } from '@handy-common-utils/promise-utils';
66
49
 
67
- // withRetry(...)
68
- const result = await withRetry(() => doSomething(), [100, 200, 300, 500, 800, 1000]);
69
- const result2 = await withRetry(() => doSomething(), Array.from({length: 10}, (_v, i) => 1000 * Math.min(FIBONACCI_SEQUENCE[i], 10)), err => err.statusCode === 429);
70
- const result3 = await withRetry(() => doSomething(), attempt => attempt <= 8 ? 1000 * Math.min(EXPONENTIAL_SEQUENCE[attempt - 1], 10) : undefined, err => err.statusCode === 429);
71
- statusCode === 429);
50
+ // Import-focused example — the actual usage is the same as using PromiseUtils.
51
+ const result = await withRetry(() => doSomething(), [100, 200, 300]);
52
+ const p = delayedResolve(100, 'ok');
53
+ const c = cancellableDelayedReject(2000, 'timeout-reason');
54
+ // c.stop() can cancel the scheduled rejection before it fires
55
+ ```
72
56
 
73
- // Capture errors in the returned array
74
- const attributesAndPossibleErrors = await PromiseUtils.inParallel(5, topicArns, async (topicArn) => {
75
- const topicAttributes = (await sns.getTopicAttributes({ TopicArn: topicArn }).promise()).Attributes!;
76
- return topicAttributes;
77
- });
57
+ ## Quick examples
78
58
 
79
- // Abort on the first error
80
- let results: Array<JobResult>;
59
+ ### Timers
60
+
61
+ ```javascript
62
+ // delayedResolve / delayedReject
63
+ await delayedResolve(50, 'ok');
64
+
65
+ // cancellableDelayedResolve: returns { stop, promise }
66
+ const { stop, promise } = cancellableDelayedResolve(1000, () => Promise.resolve('ready'));
67
+ // cancel before it fires
68
+ stop();
69
+ ```
70
+
71
+ `delayedReject` and `cancellableDelayedReject` are similar.
72
+
73
+ ### Concurrency & Parallelism
74
+
75
+ ```javascript
76
+ // withConcurrency: abort remaining on first error
81
77
  try {
82
- results = await PromiseUtils.withConcurrency(100, jobs, async (job) => processor.process(job));
83
- } catch (error) {
84
- // handle the error
78
+ await withConcurrency(5, jobs, async (job) => process(job));
79
+ } catch (err) {
80
+ // an error occurred and remaining jobs may not have been started
85
81
  }
86
82
 
83
+ // inParallel: collect all results and errors
84
+ const results = await inParallel(5, jobs, async (job) => process(job));
85
+ // results contains either values or error objects in the original order
86
+ ```
87
+
88
+ ### Scheduling & Utilities
89
+
90
+ ```javascript
91
+ // runPeriodically: schedule repeated work
92
+ const controller = runPeriodically(async (i) => {
93
+ console.log('iteration', i);
94
+ await delayedResolve(10);
95
+ }, 100, { maxExecutions: 5 });
96
+ ...
97
+ controller.stop(); // stop now
98
+ await controller.done; // wait until it stops
99
+
100
+ // synchronized: lock a resource
101
+ await PromiseUtils.synchronized('my-lock', async () => {
102
+ // only one callback for 'my-lock' runs at a time
103
+ });
87
104
  ```
88
105
 
89
106
  # API
@@ -143,11 +160,19 @@ PromiseUtils.withRetry(() => doSomething(), FIBONACCI_SEQUENCE.slice(0, 5).map(n
143
160
 
144
161
  ### Functions
145
162
 
146
- #### delayedReject
163
+ #### cancellableDelayedReject
147
164
 
148
- ▸ **delayedReject**\<`T`, `R`\>(`ms`, `reason`): `Promise`\<`T`\>
165
+ ▸ **cancellableDelayedReject**\<`T`, `R`\>(`ms`, `reason`): `Object`
166
+
167
+ Creates a cancellable timer that will reject after a specified number of milliseconds.
149
168
 
150
- See [delayedReject](#delayedreject) for full documentation.
169
+ The returned object contains:
170
+ - stop() to cancel the scheduled rejection (if called before the timer fires). Calling
171
+ stop() prevents the promise from being settled by this timer.
172
+ - promise which will reject with the supplied reason (or the value returned by the
173
+ reason function) after ms milliseconds unless stop() is called first.
174
+
175
+ If the reason is a PromiseLike that rejects, its rejection value will be used as the rejection reason.
151
176
 
152
177
  ##### Type parameters
153
178
 
@@ -158,22 +183,114 @@ See [delayedReject](#delayedreject) for full documentation.
158
183
 
159
184
  ##### Parameters
160
185
 
186
+ | Name | Type | Description |
187
+ | :------ | :------ | :------ |
188
+ | `ms` | `number` | The number of milliseconds after which the scheduled rejection will occur. |
189
+ | `reason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> | The reason for the rejection, or a function that supplies the reason. |
190
+
191
+ ##### Returns
192
+
193
+ `Object`
194
+
195
+ An object with stop() and promise.
196
+
197
+ | Name | Type |
198
+ | :------ | :------ |
199
+ | `promise` | `Promise`\<`T`\> |
200
+ | `stop` | () => `void` |
201
+
202
+ ___
203
+
204
+ #### cancellableDelayedResolve
205
+
206
+ ▸ **cancellableDelayedResolve**\<`T`\>(`ms`, `result?`): `Object`
207
+
208
+ Creates a cancellable timer that will resolve after a specified number of milliseconds.
209
+
210
+ The returned object contains:
211
+ - stop() to cancel the scheduled resolution (if called before the timer fires). Calling
212
+ stop() prevents the promise from being settled by this timer.
213
+ - promise which will resolve with the supplied result (or the value returned by the
214
+ result function) after ms milliseconds unless stop() is called first.
215
+
216
+ If the result is a PromiseLike, its resolution value will be used as the resolved value.
217
+
218
+ ##### Type parameters
219
+
220
+ | Name |
221
+ | :------ |
222
+ | `T` |
223
+
224
+ ##### Parameters
225
+
226
+ | Name | Type | Description |
227
+ | :------ | :------ | :------ |
228
+ | `ms` | `number` | The number of milliseconds after which the scheduled resolution will occur. |
229
+ | `result?` | `T` \| `PromiseLike`\<`T`\> \| () => `T` \| `PromiseLike`\<`T`\> | The result to be resolved by the Promise, or a function that supplies the result. |
230
+
231
+ ##### Returns
232
+
233
+ `Object`
234
+
235
+ An object with stop() and promise.
236
+
237
+ | Name | Type |
238
+ | :------ | :------ |
239
+ | `promise` | `Promise`\<`T`\> |
240
+ | `stop` | () => `void` |
241
+
242
+ ___
243
+
244
+ #### delayedReject
245
+
246
+ ▸ **delayedReject**\<`T`, `R`\>(`ms`, `reason`): `Promise`\<`T`\>
247
+
248
+ Creates a Promise that rejects after a specified number of milliseconds.
249
+
250
+ The reason argument may be:
251
+ - a value to reject with,
252
+ - a PromiseLike whose rejection will be adopted by the returned Promise, or
253
+ - a function which is invoked when the timer fires and may return a value or a PromiseLike.
254
+
255
+ If reason is a function, it is called when the timer elapses; if it returns a Promise,
256
+ the returned Promise will reject with that Promise's rejection reason (or reject with the
257
+ returned value if it resolves).
258
+
259
+ ##### Type parameters
260
+
161
261
  | Name | Type |
162
262
  | :------ | :------ |
163
- | `ms` | `number` |
164
- | `reason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> |
263
+ | `T` | `never` |
264
+ | `R` | `any` |
265
+
266
+ ##### Parameters
267
+
268
+ | Name | Type | Description |
269
+ | :------ | :------ | :------ |
270
+ | `ms` | `number` | The number of milliseconds after which the created Promise will reject. |
271
+ | `reason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> | The reason for the rejection, or a function that supplies the reason. |
165
272
 
166
273
  ##### Returns
167
274
 
168
275
  `Promise`\<`T`\>
169
276
 
277
+ A Promise that rejects with the specified reason after the specified delay.
278
+
170
279
  ___
171
280
 
172
281
  #### delayedResolve
173
282
 
174
283
  ▸ **delayedResolve**\<`T`\>(`ms`, `result?`): `Promise`\<`T`\>
175
284
 
176
- See [delayedResolve](#delayedresolve) for full documentation.
285
+ Creates a Promise that resolves after a specified number of milliseconds.
286
+
287
+ The result argument may be:
288
+ - a value to resolve with,
289
+ - a PromiseLike whose resolution will be adopted by the returned Promise, or
290
+ - a function which is invoked when the timer fires and may return a value or a PromiseLike.
291
+
292
+ If result is a function, it is called when the timer elapses; if it returns a Promise,
293
+ the returned Promise will adopt that Promise's outcome.
177
294
 
178
295
  ##### Type parameters
179
296
 
@@ -183,22 +300,32 @@ See [delayedResolve](#delayedresolve) for full documentation.
183
300
 
184
301
  ##### Parameters
185
302
 
186
- | Name | Type |
187
- | :------ | :------ |
188
- | `ms` | `number` |
189
- | `result?` | `T` \| `PromiseLike`\<`T`\> \| () => `T` \| `PromiseLike`\<`T`\> |
303
+ | Name | Type | Description |
304
+ | :------ | :------ | :------ |
305
+ | `ms` | `number` | The number of milliseconds after which the created Promise will resolve. |
306
+ | `result?` | `T` \| `PromiseLike`\<`T`\> \| () => `T` \| `PromiseLike`\<`T`\> | The result to be resolved by the Promise, or a function that supplies the result. |
190
307
 
191
308
  ##### Returns
192
309
 
193
310
  `Promise`\<`T`\>
194
311
 
312
+ A Promise that resolves with the specified result after the specified delay.
313
+
195
314
  ___
196
315
 
197
316
  #### inParallel
198
317
 
199
318
  ▸ **inParallel**\<`Data`, `Result`, `TError`\>(`parallelism`, `jobs`, `operation`, `options?`): `Promise`\<(`Result` \| `TError`)[]\>
200
319
 
201
- See [inParallel](#inparallel) for full documentation.
320
+ Executes multiple jobs/operations in parallel. By default, all operations are executed regardless of any failures.
321
+ In most cases, using withConcurrency might be more convenient.
322
+
323
+ By default, this function does not throw or reject an error when any job/operation fails.
324
+ Errors from operations are returned alongside results in the returned array.
325
+ This function only resolves when all jobs/operations are settled (either resolved or rejected).
326
+
327
+ If options.abortOnError is set to true, this function throws (or rejects with) an error immediately when any job/operation fails.
328
+ In this mode, some jobs/operations may not be executed if one fails.
202
329
 
203
330
  ##### Type parameters
204
331
 
@@ -210,43 +337,51 @@ See [inParallel](#inparallel) for full documentation.
210
337
 
211
338
  ##### Parameters
212
339
 
213
- | Name | Type |
214
- | :------ | :------ |
215
- | `parallelism` | `number` |
216
- | `jobs` | `Iterable`\<`Data`\> |
217
- | `operation` | (`job`: `Data`, `index`: `number`) => `Promise`\<`Result`\> |
218
- | `options?` | `Object` |
219
- | `options.abortOnError` | `boolean` |
340
+ | Name | Type | Description |
341
+ | :------ | :------ | :------ |
342
+ | `parallelism` | `number` | The number of jobs/operations to run concurrently. |
343
+ | `jobs` | `Iterable`\<`Data`\> | The job data to be processed. This function can safely handle an infinite or unknown number of elements. |
344
+ | `operation` | (`job`: `Data`, `index`: `number`) => `Promise`\<`Result`\> | The function that processes job data asynchronously. |
345
+ | `options?` | `Object` | Options to control the function's behavior. |
346
+ | `options.abortOnError` | `boolean` | If true, the function aborts and throws an error on the first failed operation. |
220
347
 
221
348
  ##### Returns
222
349
 
223
350
  `Promise`\<(`Result` \| `TError`)[]\>
224
351
 
352
+ A promise that resolves to an array containing the results of the operations.
353
+ Each element is either a fulfilled result or a rejected error/reason.
354
+ The results or errors in the returned array are in the same order as the corresponding elements in the jobs array.
355
+
225
356
  ___
226
357
 
227
358
  #### promiseState
228
359
 
229
360
  ▸ **promiseState**(`p`): `Promise`\<[`PromiseState`](#enumspromisestatemd)\>
230
361
 
231
- See [promiseState](#promisestate) for full documentation.
362
+ Retrieves the state of the specified Promise.
363
+ Note: The returned value is a Promise that resolves immediately.
232
364
 
233
365
  ##### Parameters
234
366
 
235
- | Name | Type |
236
- | :------ | :------ |
237
- | `p` | `Promise`\<`any`\> |
367
+ | Name | Type | Description |
368
+ | :------ | :------ | :------ |
369
+ | `p` | `Promise`\<`any`\> | The Promise whose state is to be determined. |
238
370
 
239
371
  ##### Returns
240
372
 
241
373
  `Promise`\<[`PromiseState`](#enumspromisestatemd)\>
242
374
 
375
+ A Promise that resolves immediately with the state of the input Promise.
376
+
243
377
  ___
244
378
 
245
379
  #### repeat
246
380
 
247
381
  ▸ **repeat**\<`Result`, `Param`, `Collection`\>(`operation`, `nextParameter`, `collect`, `initialCollection`, `initialParameter?`): `Promise`\<`Collection`\>
248
382
 
249
- See [repeat](#repeat) for full documentation.
383
+ Executes an operation repeatedly and collects all the results.
384
+ This function is very useful for many scenarios, such like client-side pagination.
250
385
 
251
386
  ##### Type parameters
252
387
 
@@ -258,25 +393,27 @@ See [repeat](#repeat) for full documentation.
258
393
 
259
394
  ##### Parameters
260
395
 
261
- | Name | Type |
262
- | :------ | :------ |
263
- | `operation` | (`parameter`: `Partial`\<`Param`\>) => `Promise`\<`Result`\> |
264
- | `nextParameter` | (`response`: `Result`) => ``null`` \| `Partial`\<`Param`\> \| `Promise`\<`Partial`\<`Param`\>\> |
265
- | `collect` | (`collection`: `Collection`, `result`: `Result`) => `Collection` |
266
- | `initialCollection` | `Collection` |
267
- | `initialParameter` | `Partial`\<`Param`\> |
396
+ | Name | Type | Description |
397
+ | :------ | :------ | :------ |
398
+ | `operation` | (`parameter`: `Partial`\<`Param`\>) => `Promise`\<`Result`\> | A function that takes a parameter as input and returns a result. Typically, the parameter has optional fields to control paging. |
399
+ | `nextParameter` | (`response`: `Result`) => ``null`` \| `Partial`\<`Param`\> \| `Promise`\<`Partial`\<`Param`\>\> | A function for calculating the next parameter from the operation result. Normally, this parameter controls paging. This function should return null when no further invocation of the operation function is desired. If further invocation is desired, the return value of this function can be a Promise or a non-Promise value. |
400
+ | `collect` | (`collection`: `Collection`, `result`: `Result`) => `Collection` | A function for merging the operation result into the collection. |
401
+ | `initialCollection` | `Collection` | The initial collection, which will be the first argument passed to the first invocation of the collect function. |
402
+ | `initialParameter` | `Partial`\<`Param`\> | The parameter for the first operation. |
268
403
 
269
404
  ##### Returns
270
405
 
271
406
  `Promise`\<`Collection`\>
272
407
 
408
+ A promise that resolves to a collection of all the results returned by the operation function.
409
+
273
410
  ___
274
411
 
275
- #### synchronised
412
+ #### runPeriodically
276
413
 
277
- ▸ **synchronised**\<`T`\>(`lock`, `operation`): `Promise`\<`T`\>
414
+ ▸ **runPeriodically**\<`T`\>(`operation`, `interval`, `options?`): `Object`
278
415
 
279
- See [synchronised](#synchronised) for full documentation.
416
+ Runs an operation periodically with configurable intervals and stopping conditions.
280
417
 
281
418
  ##### Type parameters
282
419
 
@@ -286,22 +423,65 @@ See [synchronised](#synchronised) for full documentation.
286
423
 
287
424
  ##### Parameters
288
425
 
426
+ | Name | Type | Description |
427
+ | :------ | :------ | :------ |
428
+ | `operation` | (`iteration`: `number`) => `T` \| `Promise`\<`T`\> | The operation to run periodically. |
429
+ | `interval` | `number` \| `number`[] \| (`iteration`: `number`) => `undefined` \| `number` | The interval (ms), array of intervals, or function returning interval per iteration. |
430
+ | `options?` | `Object` | Options for maxExecutions, maxDurationMs, and schedule type. |
431
+ | `options.maxDurationMs?` | `number` | - |
432
+ | `options.maxExecutions?` | `number` | - |
433
+ | `options.schedule?` | ``"delayAfterEnd"`` \| ``"delayBetweenStarts"`` | - |
434
+
435
+ ##### Returns
436
+
437
+ `Object`
438
+
439
+ An object with stop() and done Promise which resolves when the periodic runner stops (or rejects if the operation errors).
440
+
289
441
  | Name | Type |
290
442
  | :------ | :------ |
291
- | `lock` | `any` |
292
- | `operation` | (`previousState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousSettledState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousResult`: `any`) => `Promise`\<`T`\> |
443
+ | `done` | `Promise`\<`void`\> |
444
+ | `stop` | () => `void` |
445
+
446
+ ___
447
+
448
+ #### synchronised
449
+
450
+ ▸ **synchronised**\<`T`\>(`lock`, `operation`): `Promise`\<`T`\>
451
+
452
+ This is just another spelling of synchronized.
453
+
454
+ ##### Type parameters
455
+
456
+ | Name |
457
+ | :------ |
458
+ | `T` |
459
+
460
+ ##### Parameters
461
+
462
+ | Name | Type | Description |
463
+ | :------ | :------ | :------ |
464
+ | `lock` | `any` | The object (such as a string, a number, or this in a class) used to identify the lock. |
465
+ | `operation` | (`previousState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousSettledState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousResult`: `any`) => `Promise`\<`T`\> | The function that performs the computation and returns a Promise. |
293
466
 
294
467
  ##### Returns
295
468
 
296
469
  `Promise`\<`T`\>
297
470
 
471
+ The result of the operation function.
472
+
298
473
  ___
299
474
 
300
475
  #### synchronized
301
476
 
302
477
  ▸ **synchronized**\<`T`\>(`lock`, `operation`): `Promise`\<`T`\>
303
478
 
304
- See [synchronized](#synchronized) for full documentation.
479
+ Provides mutual exclusion similar to synchronized in Java.
480
+ Ensures no concurrent execution of any operation function associated with the same lock.
481
+ The operation function has access to the state (when synchronized is called),
482
+ settledState (when the operation function is called),
483
+ and result (either the fulfilled result or the rejected reason) of the previous operation.
484
+ If there is no previous invocation, state, settledState, and result will all be undefined.
305
485
 
306
486
  ##### Type parameters
307
487
 
@@ -311,22 +491,28 @@ See [synchronized](#synchronized) for full documentation.
311
491
 
312
492
  ##### Parameters
313
493
 
314
- | Name | Type |
315
- | :------ | :------ |
316
- | `lock` | `any` |
317
- | `operation` | (`previousState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousSettledState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousResult`: `any`) => `Promise`\<`T`\> |
494
+ | Name | Type | Description |
495
+ | :------ | :------ | :------ |
496
+ | `lock` | `any` | The object (such as a string, a number, or this in a class) used to identify the lock. |
497
+ | `operation` | (`previousState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousSettledState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousResult`: `any`) => `Promise`\<`T`\> | The function that performs the computation and returns a Promise. |
318
498
 
319
499
  ##### Returns
320
500
 
321
501
  `Promise`\<`T`\>
322
502
 
503
+ The result of the operation function.
504
+
323
505
  ___
324
506
 
325
507
  #### timeoutReject
326
508
 
327
509
  ▸ **timeoutReject**\<`T`, `R`\>(`operation`, `ms`, `rejectReason`): `Promise`\<`T`\>
328
510
 
329
- See [timeoutReject](#timeoutreject) for full documentation.
511
+ Applies a timeout to a Promise or a function that returns a Promise.
512
+ If the timeout occurs, the returned Promise rejects with the specified reason.
513
+ If the timeout does not occur, the returned Promise resolves or rejects based on the outcome of the original Promise.
514
+ If the rejectReason parameter is a function and the timeout does not occur, the function will not be called.
515
+ Note: The rejection of the operation parameter is not handled by this function. You may want to handle it outside this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously."
330
516
 
331
517
  ##### Type parameters
332
518
 
@@ -337,23 +523,30 @@ See [timeoutReject](#timeoutreject) for full documentation.
337
523
 
338
524
  ##### Parameters
339
525
 
340
- | Name | Type |
341
- | :------ | :------ |
342
- | `operation` | `Promise`\<`T`\> \| () => `Promise`\<`T`\> |
343
- | `ms` | `number` |
344
- | `rejectReason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> |
526
+ | Name | Type | Description |
527
+ | :------ | :------ | :------ |
528
+ | `operation` | `Promise`\<`T`\> \| () => `Promise`\<`T`\> | The original Promise or a function that returns a Promise to which the timeout will be applied. |
529
+ | `ms` | `number` | The number of milliseconds for the timeout. |
530
+ | `rejectReason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> | The reason to reject with if the timeout occurs, or a function that supplies the reason. |
345
531
 
346
532
  ##### Returns
347
533
 
348
534
  `Promise`\<`T`\>
349
535
 
536
+ A new Promise that rejects with the specified reason if the timeout occurs.
537
+
350
538
  ___
351
539
 
352
540
  #### timeoutResolve
353
541
 
354
542
  ▸ **timeoutResolve**\<`T`\>(`operation`, `ms`, `result?`): `Promise`\<`T`\>
355
543
 
356
- See [timeoutResolve](#timeoutresolve) for full documentation.
544
+ Applies a timeout to a Promise or a function that returns a Promise.
545
+ If the timeout occurs, the returned Promise resolves to the specified result.
546
+ If the timeout does not occur, the returned Promise resolves or rejects based on the outcome of the original Promise.
547
+ If the result parameter is a function and the timeout does not occur, the function will not be called.
548
+ Note: The rejection of the operation parameter is not handled by this function.
549
+ You may want to handle it outside this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously."
357
550
 
358
551
  ##### Type parameters
359
552
 
@@ -363,23 +556,25 @@ See [timeoutResolve](#timeoutresolve) for full documentation.
363
556
 
364
557
  ##### Parameters
365
558
 
366
- | Name | Type |
367
- | :------ | :------ |
368
- | `operation` | `Promise`\<`T`\> \| () => `Promise`\<`T`\> |
369
- | `ms` | `number` |
370
- | `result?` | `T` \| `PromiseLike`\<`T`\> \| () => `T` \| `PromiseLike`\<`T`\> |
559
+ | Name | Type | Description |
560
+ | :------ | :------ | :------ |
561
+ | `operation` | `Promise`\<`T`\> \| () => `Promise`\<`T`\> | The original Promise or a function that returns a Promise to which the timeout will be applied. |
562
+ | `ms` | `number` | The number of milliseconds for the timeout. |
563
+ | `result?` | `T` \| `PromiseLike`\<`T`\> \| () => `T` \| `PromiseLike`\<`T`\> | The result to resolve with if the timeout occurs, or a function that supplies the result. |
371
564
 
372
565
  ##### Returns
373
566
 
374
567
  `Promise`\<`T`\>
375
568
 
569
+ A new Promise that resolves to the specified result if the timeout occurs.
570
+
376
571
  ___
377
572
 
378
573
  #### withConcurrency
379
574
 
380
575
  ▸ **withConcurrency**\<`Data`, `Result`\>(`concurrency`, `jobs`, `operation`): `Promise`\<`Result`[]\>
381
576
 
382
- See [withConcurrency](#withconcurrency) for full documentation.
577
+ Executes multiple jobs/operations with a specified level of concurrency.
383
578
 
384
579
  ##### Type parameters
385
580
 
@@ -390,23 +585,26 @@ See [withConcurrency](#withconcurrency) for full documentation.
390
585
 
391
586
  ##### Parameters
392
587
 
393
- | Name | Type |
394
- | :------ | :------ |
395
- | `concurrency` | `number` |
396
- | `jobs` | `Iterable`\<`Data`\> |
397
- | `operation` | (`job`: `Data`, `index`: `number`) => `Promise`\<`Result`\> |
588
+ | Name | Type | Description |
589
+ | :------ | :------ | :------ |
590
+ | `concurrency` | `number` | The number of jobs/operations to run concurrently. |
591
+ | `jobs` | `Iterable`\<`Data`\> | The job data to be processed. This function can handle an infinite or unknown number of elements safely. |
592
+ | `operation` | (`job`: `Data`, `index`: `number`) => `Promise`\<`Result`\> | The function that processes job data asynchronously. |
398
593
 
399
594
  ##### Returns
400
595
 
401
596
  `Promise`\<`Result`[]\>
402
597
 
598
+ A promise that resolves to an array containing the results from the operation function.
599
+ The results in the returned array are in the same order as the corresponding elements in the jobs array.
600
+
403
601
  ___
404
602
 
405
603
  #### withRetry
406
604
 
407
605
  ▸ **withRetry**\<`Result`, `TError`\>(`operation`, `backoff`, `shouldRetry?`): `Promise`\<`Result`\>
408
606
 
409
- See [withRetry](#withretry) for full documentation.
607
+ Repeatedly performs an operation until a specified criteria is met.
410
608
 
411
609
  ##### Type parameters
412
610
 
@@ -417,16 +615,18 @@ See [withRetry](#withretry) for full documentation.
417
615
 
418
616
  ##### Parameters
419
617
 
420
- | Name | Type |
421
- | :------ | :------ |
422
- | `operation` | (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `Promise`\<`Result`\> |
423
- | `backoff` | `number`[] \| (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `undefined` \| `number` |
424
- | `shouldRetry` | (`previousError`: `undefined` \| `TError`, `previousResult`: `undefined` \| `Result`, `attempt`: `number`) => `boolean` |
618
+ | Name | Type | Description |
619
+ | :------ | :------ | :------ |
620
+ | `operation` | (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `Promise`\<`Result`\> | A function that outputs a Promise result. Typically, the operation does not use its arguments. |
621
+ | `backoff` | `number`[] \| (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `undefined` \| `number` | An array of retry backoff periods (in milliseconds) or a function for calculating them. |
622
+ | `shouldRetry` | (`previousError`: `undefined` \| `TError`, `previousResult`: `undefined` \| `Result`, `attempt`: `number`) => `boolean` | A predicate function for deciding whether another call to the operation should occur. |
425
623
 
426
624
  ##### Returns
427
625
 
428
626
  `Promise`\<`Result`\>
429
627
 
628
+ A promise of the operation result, potentially with retries applied.
629
+
430
630
  ## Classes
431
631
 
432
632
 
@@ -442,12 +642,103 @@ See [withRetry](#withretry) for full documentation.
442
642
 
443
643
  #### Methods
444
644
 
645
+ ##### cancellableDelayedReject
646
+
647
+ ▸ `Static` **cancellableDelayedReject**\<`T`, `R`\>(`ms`, `reason`): `Object`
648
+
649
+ Creates a cancellable timer that will reject after a specified number of milliseconds.
650
+
651
+ The returned object contains:
652
+ - `stop()` to cancel the scheduled rejection (if called before the timer fires). Calling
653
+ `stop()` prevents the promise from being settled by this timer.
654
+ - `promise` which will reject with the supplied `reason` (or the value returned by the
655
+ `reason` function) after `ms` milliseconds unless `stop()` is called first.
656
+
657
+ If the `reason` is a PromiseLike that rejects, its rejection value will be used as the rejection reason.
658
+
659
+ ###### Type parameters
660
+
661
+ | Name | Type |
662
+ | :------ | :------ |
663
+ | `T` | `never` |
664
+ | `R` | `any` |
665
+
666
+ ###### Parameters
667
+
668
+ | Name | Type | Description |
669
+ | :------ | :------ | :------ |
670
+ | `ms` | `number` | The number of milliseconds after which the scheduled rejection will occur. |
671
+ | `reason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> | The reason for the rejection, or a function that supplies the reason. |
672
+
673
+ ###### Returns
674
+
675
+ `Object`
676
+
677
+ An object with `stop()` and `promise`.
678
+
679
+ | Name | Type |
680
+ | :------ | :------ |
681
+ | `promise` | `Promise`\<`T`\> |
682
+ | `stop` | () => `void` |
683
+
684
+ ___
685
+
686
+ ##### cancellableDelayedResolve
687
+
688
+ ▸ `Static` **cancellableDelayedResolve**\<`T`\>(`ms`, `result?`): `Object`
689
+
690
+ Creates a cancellable timer that will resolve after a specified number of milliseconds.
691
+
692
+ The returned object contains:
693
+ - `stop()` to cancel the scheduled resolution (if called before the timer fires). Calling
694
+ `stop()` prevents the promise from being settled by this timer.
695
+ - `promise` which will resolve with the supplied `result` (or the value returned by the
696
+ `result` function) after `ms` milliseconds unless `stop()` is called first.
697
+
698
+ Note: If the `result` is a function that returns a Promise, the returned `promise` will
699
+ resolve with that Promise's resolution (i.e. it behaves like resolving with a PromiseLike).
700
+
701
+ ###### Type parameters
702
+
703
+ | Name |
704
+ | :------ |
705
+ | `T` |
706
+
707
+ ###### Parameters
708
+
709
+ | Name | Type | Description |
710
+ | :------ | :------ | :------ |
711
+ | `ms` | `number` | The number of milliseconds after which the scheduled resolution will occur. |
712
+ | `result?` | `T` \| `PromiseLike`\<`T`\> \| () => `T` \| `PromiseLike`\<`T`\> | The result to be resolved by the Promise, or a function that supplies the result. |
713
+
714
+ ###### Returns
715
+
716
+ `Object`
717
+
718
+ An object with `stop()` and `promise`.
719
+
720
+ | Name | Type |
721
+ | :------ | :------ |
722
+ | `promise` | `Promise`\<`T`\> |
723
+ | `stop` | () => `void` |
724
+
725
+ ___
726
+
445
727
  ##### delayedReject
446
728
 
447
729
  ▸ `Static` **delayedReject**\<`T`, `R`\>(`ms`, `reason`): `Promise`\<`T`\>
448
730
 
449
731
  Creates a Promise that rejects after a specified number of milliseconds.
450
732
 
733
+ The `reason` argument may be:
734
+ - a value to reject with,
735
+ - a PromiseLike whose rejection will be adopted by the returned Promise, or
736
+ - a function which is invoked when the timer fires and may return a value or a PromiseLike.
737
+
738
+ If `reason` is a function, it is called when the timer elapses; if it returns a Promise,
739
+ the returned Promise will reject with that Promise's rejection reason (or reject with the
740
+ returned value if it resolves).
741
+
451
742
  ###### Type parameters
452
743
 
453
744
  | Name | Type |
@@ -460,13 +751,13 @@ Creates a Promise that rejects after a specified number of milliseconds.
460
751
  | Name | Type | Description |
461
752
  | :------ | :------ | :------ |
462
753
  | `ms` | `number` | The number of milliseconds after which the created Promise will reject. |
463
- | `reason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> | The reason for the rejection, or a function that supplies the reason. If the reason is a rejected Promise, the outcome of it will be the rejection reason of the returned Promise. |
754
+ | `reason` | `R` \| `PromiseLike`\<`R`\> \| () => `R` \| `PromiseLike`\<`R`\> | The reason for the rejection, or a function that supplies the reason. |
464
755
 
465
756
  ###### Returns
466
757
 
467
758
  `Promise`\<`T`\>
468
759
 
469
- A new Promise that rejects with the specified reason after the specified delay.
760
+ A Promise that rejects with the specified reason after the specified delay.
470
761
 
471
762
  ___
472
763
 
@@ -476,6 +767,14 @@ ___
476
767
 
477
768
  Creates a Promise that resolves after a specified number of milliseconds.
478
769
 
770
+ The `result` argument may be:
771
+ - a value to resolve with,
772
+ - a PromiseLike whose resolution will be adopted by the returned Promise, or
773
+ - a function which is invoked when the timer fires and may return a value or a PromiseLike.
774
+
775
+ If `result` is a function, it is called when the timer elapses; if it returns a Promise,
776
+ the returned Promise will adopt that Promise's outcome.
777
+
479
778
  ###### Type parameters
480
779
 
481
780
  | Name |
@@ -493,7 +792,7 @@ Creates a Promise that resolves after a specified number of milliseconds.
493
792
 
494
793
  `Promise`\<`T`\>
495
794
 
496
- A new Promise that resolves with the specified result after the specified delay.
795
+ A Promise that resolves with the specified result after the specified delay.
497
796
 
498
797
  ___
499
798
 
@@ -622,6 +921,67 @@ const domainNameObjects = await PromiseUtils.repeat(
622
921
 
623
922
  ___
624
923
 
924
+ ##### runPeriodically
925
+
926
+ ▸ `Static` **runPeriodically**\<`T`\>(`operation`, `interval`, `options?`): `Object`
927
+
928
+ Runs an operation periodically with configurable intervals and stopping conditions.
929
+
930
+ - `interval` may be a single number (ms), an array of numbers, or a function
931
+ that receives the iteration number (starting at 1) and returns the next
932
+ interval in milliseconds or `undefined` to stop.
933
+ - If the interval array runs out of elements or the function returns `undefined`
934
+ (or a negative value), no further invocations will be scheduled.
935
+
936
+ Options:
937
+ - `maxExecutions` stop after N runs (inclusive).
938
+ - `maxDurationMs` stop after elapsed ms since the first scheduled start.
939
+ - `schedule` controls how the interval is measured:
940
+ - `'delayAfterEnd'`: wait the interval after the previous operation completes
941
+ before scheduling the next one (equivalent to a fixed delay between ends).
942
+ - `'delayBetweenStarts'`: keep start times on a regular schedule (interval measured
943
+ between the starts of successive operations).
944
+ The default schedule is `'delayBetweenStarts'`.
945
+
946
+ Returns an object with `stop()` to cancel further executions and `done` which
947
+ resolves when the periodic runner stops. If the provided `operation` throws or
948
+ rejects, the `done` promise will reject with that error so callers can handle it.
949
+
950
+ Note: The first invocation of `operation` is scheduled after the first interval
951
+ elapses (i.e. this function does NOT call `operation` immediately). If you need
952
+ an immediate run, invoke `operation(1)` yourself before calling `runPeriodically`.
953
+
954
+ ###### Type parameters
955
+
956
+ | Name | Description |
957
+ | :------ | :------ |
958
+ | `T` | The operation return type (ignored by the runner; used for typing). |
959
+
960
+ ###### Parameters
961
+
962
+ | Name | Type | Description |
963
+ | :------ | :------ | :------ |
964
+ | `operation` | (`iteration`: `number`) => `T` \| `Promise`\<`T`\> | Function to run each iteration. Receives the iteration index (1-based). |
965
+ | `interval` | `number` \| `number`[] \| (`iteration`: `number`) => `undefined` \| `number` | Number \| number[] \| ((iteration: number) => number\|undefined) defining waits. |
966
+ | `options?` | `Object` | Optional configuration. |
967
+ | `options.maxDurationMs?` | `number` | - |
968
+ | `options.maxExecutions?` | `number` | - |
969
+ | `options.schedule?` | ``"delayAfterEnd"`` \| ``"delayBetweenStarts"`` | - |
970
+
971
+ ###### Returns
972
+
973
+ `Object`
974
+
975
+ An object containing `stop()` to cancel further executions and `done` Promise
976
+ which resolves when the periodic runner stops (or rejects if the operation errors).
977
+
978
+ | Name | Type |
979
+ | :------ | :------ |
980
+ | `done` | `Promise`\<`void`\> |
981
+ | `stop` | () => `void` |
982
+
983
+ ___
984
+
625
985
  ##### synchronised
626
986
 
627
987
  ▸ `Static` **synchronised**\<`T`\>(`lock`, `operation`): `Promise`\<`T`\>