@handy-common-utils/promise-utils 1.2.7 → 1.4.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
@@ -1,7 +1,7 @@
1
1
  # @handy-common-utils/promise-utils
2
2
 
3
3
  These Promise related utilities have 100% test coverage. The package is tiny because there is no dependency on any other package.
4
- Functions provided are `repeat`, `withRetry`, `inParallel`, `delayedResolve`, `delayedReject`, `timoutResolve`, `timeoutReject`, `promiseState`, `synchronized`, etc.
4
+ Functions provided are `repeat`, `withRetry`, `inParallel`, `delayedResolve`, `delayedReject`, `timeoutResolve`, `timeoutReject`, `promiseState`, `synchronized`, etc.
5
5
 
6
6
  [![Version](https://img.shields.io/npm/v/@handy-common-utils/promise-utils.svg)](https://npmjs.org/package/@handy-common-utils/promise-utils)
7
7
  [![Downloads/week](https://img.shields.io/npm/dw/@handy-common-utils/promise-utils.svg)](https://npmjs.org/package/@handy-common-utils/promise-utils)
@@ -76,38 +76,16 @@ await inParallel(5, topicArns, async topicArn => {
76
76
  <!-- API start -->
77
77
  <a name="readmemd"></a>
78
78
 
79
- @handy-common-utils/promise-utils
80
-
81
79
  ## @handy-common-utils/promise-utils
82
80
 
83
- ### Table of contents
84
-
85
- #### Enumerations
81
+ ### Enumerations
86
82
 
87
83
  - [PromiseState](#enumspromisestatemd)
88
84
 
89
- #### Classes
85
+ ### Classes
90
86
 
91
87
  - [PromiseUtils](#classespromiseutilsmd)
92
88
 
93
- #### Variables
94
-
95
- - [EXPONENTIAL\_SEQUENCE](#exponential_sequence)
96
- - [FIBONACCI\_SEQUENCE](#fibonacci_sequence)
97
-
98
- #### Functions
99
-
100
- - [delayedReject](#delayedreject)
101
- - [delayedResolve](#delayedresolve)
102
- - [inParallel](#inparallel)
103
- - [promiseState](#promisestate)
104
- - [repeat](#repeat)
105
- - [synchronised](#synchronised)
106
- - [synchronized](#synchronized)
107
- - [timeoutReject](#timeoutreject)
108
- - [timeoutResolve](#timeoutresolve)
109
- - [withRetry](#withretry)
110
-
111
89
  ### Variables
112
90
 
113
91
  #### EXPONENTIAL\_SEQUENCE
@@ -117,19 +95,19 @@ await inParallel(5, topicArns, async topicArn => {
117
95
  Array of 25 exponential numbers starting from 1 up to 33554432.
118
96
  It can be used to form your own backoff interval array.
119
97
 
120
- **`example`**
121
- ```javascript
98
+ **`Example`**
122
99
 
100
+ ```ts
123
101
  // 1ms, 2ms, 4ms, 8ms, 16ms, 32ms
124
102
  PromiseUtils.withRetry(() => doSomething(), EXPONENTIAL_SEQUENCE.slice(0, 5), err => err.statusCode === 429);
125
103
  // 1s, 2s, 4s, 8s, 10s, 10s, 10s, 10s, 10s, 10s
126
104
  PromiseUtils.withRetry(() => doSomething(), Array.from({length: 10}, (_v, i) => 1000 * Math.min(EXPONENTIAL_SEQUENCE[i], 10)), err => err.statusCode === 429);
127
105
  // with +-10% randomness: 1s, 2s, 4s, 8s
128
106
  PromiseUtils.withRetry(() => doSomething(), FIBONACCI_SEQUENCE.slice(0, 4).map(n => 1000 * n * (1 + (Math.random() - 0.5) / 5)), err => err.statusCode === 429);
107
+ ```
129
108
 
130
109
  ___
131
110
 
132
- ```
133
111
  #### FIBONACCI\_SEQUENCE
134
112
 
135
113
  • `Const` **FIBONACCI\_SEQUENCE**: `number`[]
@@ -137,43 +115,282 @@ ___
137
115
  Array of 25 Fibonacci numbers starting from 1 up to 317811.
138
116
  It can be used to form your own backoff interval array.
139
117
 
140
- **`example`**
141
- ```javascript
118
+ **`Example`**
142
119
 
120
+ ```ts
143
121
  // 1ms, 2ms, 3ms, 5ms, 8ms, 13ms
144
122
  PromiseUtils.withRetry(() => doSomething(), FIBONACCI_SEQUENCE.slice(0, 5), err => err.statusCode === 429);
145
123
  // 1s, 2s, 3s, 4s, 8s, 10s, 10s, 10s, 10s, 10s
146
124
  PromiseUtils.withRetry(() => doSomething(), Array.from({length: 10}, (_v, i) => 1000 * Math.min(FIBONACCI_SEQUENCE[i], 10)), err => err.statusCode === 429);
147
125
  // with +-10% randomness: 1s, 2s, 3s, 5s, 8s, 13s
148
126
  PromiseUtils.withRetry(() => doSomething(), FIBONACCI_SEQUENCE.slice(0, 5).map(n => 1000 * n * (1 + (Math.random() - 0.5) / 5)), err => err.statusCode === 429);
127
+ ```
149
128
 
150
- ```## Classes
129
+ ### Functions
151
130
 
131
+ #### delayedReject
152
132
 
153
- <a name="classespromiseutilsmd"></a>
133
+ **delayedReject**<`T`, `R`\>(`ms`, `reason`): `Promise`<`T`\>
154
134
 
155
- [@handy-common-utils/promise-utils](#readmemd) / PromiseUtils
135
+ See [delayedReject](#delayedreject) for full documentation.
156
136
 
157
- ### Class: PromiseUtils
137
+ ##### Type parameters
138
+
139
+ | Name | Type |
140
+ | :------ | :------ |
141
+ | `T` | `never` |
142
+ | `R` | `any` |
143
+
144
+ ##### Parameters
145
+
146
+ | Name | Type |
147
+ | :------ | :------ |
148
+ | `ms` | `number` |
149
+ | `reason` | `R` \| `PromiseLike`<`R`\> \| () => `R` \| `PromiseLike`<`R`\> |
150
+
151
+ ##### Returns
152
+
153
+ `Promise`<`T`\>
154
+
155
+ ___
156
+
157
+ #### delayedResolve
158
+
159
+ ▸ **delayedResolve**<`T`\>(`ms`, `result?`): `Promise`<`T`\>
160
+
161
+ See [delayedResolve](#delayedresolve) for full documentation.
162
+
163
+ ##### Type parameters
164
+
165
+ | Name |
166
+ | :------ |
167
+ | `T` |
168
+
169
+ ##### Parameters
170
+
171
+ | Name | Type |
172
+ | :------ | :------ |
173
+ | `ms` | `number` |
174
+ | `result?` | `T` \| `PromiseLike`<`T`\> \| () => `T` \| `PromiseLike`<`T`\> |
175
+
176
+ ##### Returns
177
+
178
+ `Promise`<`T`\>
179
+
180
+ ___
181
+
182
+ #### inParallel
183
+
184
+ ▸ **inParallel**<`Data`, `Result`, `TError`\>(`parallelism`, `jobs`, `operation`, `options?`): `Promise`<(`Result` \| `TError`)[]\>
185
+
186
+ See [inParallel](#inparallel) for full documentation.
187
+
188
+ ##### Type parameters
189
+
190
+ | Name | Type |
191
+ | :------ | :------ |
192
+ | `Data` | `Data` |
193
+ | `Result` | `Result` |
194
+ | `TError` | `Result` |
195
+
196
+ ##### Parameters
197
+
198
+ | Name | Type |
199
+ | :------ | :------ |
200
+ | `parallelism` | `number` |
201
+ | `jobs` | `Iterable`<`Data`\> |
202
+ | `operation` | (`job`: `Data`, `index`: `number`) => `Promise`<`Result`\> |
203
+ | `options?` | `Object` |
204
+ | `options.abortOnError` | `boolean` |
205
+
206
+ ##### Returns
207
+
208
+ `Promise`<(`Result` \| `TError`)[]\>
209
+
210
+ ___
211
+
212
+ #### promiseState
213
+
214
+ ▸ **promiseState**(`p`): `Promise`<[`PromiseState`](#enumspromisestatemd)\>
215
+
216
+ See [promiseState](#promisestate) for full documentation.
217
+
218
+ ##### Parameters
219
+
220
+ | Name | Type |
221
+ | :------ | :------ |
222
+ | `p` | `Promise`<`any`\> |
223
+
224
+ ##### Returns
225
+
226
+ `Promise`<[`PromiseState`](#enumspromisestatemd)\>
227
+
228
+ ___
229
+
230
+ #### repeat
231
+
232
+ ▸ **repeat**<`Result`, `Param`, `Collection`\>(`operation`, `nextParameter`, `collect`, `initialCollection`, `initialParameter?`): `Promise`<`Collection`\>
233
+
234
+ See [repeat](#repeat) for full documentation.
235
+
236
+ ##### Type parameters
237
+
238
+ | Name |
239
+ | :------ |
240
+ | `Result` |
241
+ | `Param` |
242
+ | `Collection` |
243
+
244
+ ##### Parameters
245
+
246
+ | Name | Type |
247
+ | :------ | :------ |
248
+ | `operation` | (`parameter`: `Partial`<`Param`\>) => `Promise`<`Result`\> |
249
+ | `nextParameter` | (`response`: `Result`) => ``null`` \| `Partial`<`Param`\> \| `Promise`<`Partial`<`Param`\>\> |
250
+ | `collect` | (`collection`: `Collection`, `result`: `Result`) => `Collection` |
251
+ | `initialCollection` | `Collection` |
252
+ | `initialParameter` | `Partial`<`Param`\> |
253
+
254
+ ##### Returns
255
+
256
+ `Promise`<`Collection`\>
257
+
258
+ ___
259
+
260
+ #### synchronised
261
+
262
+ ▸ **synchronised**<`T`\>(`lock`, `operation`): `Promise`<`T`\>
263
+
264
+ See [synchronised](#synchronised) for full documentation.
265
+
266
+ ##### Type parameters
267
+
268
+ | Name |
269
+ | :------ |
270
+ | `T` |
271
+
272
+ ##### Parameters
273
+
274
+ | Name | Type |
275
+ | :------ | :------ |
276
+ | `lock` | `unknown` |
277
+ | `operation` | (`previousState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousSettledState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousResult`: `any`) => `Promise`<`T`\> |
278
+
279
+ ##### Returns
280
+
281
+ `Promise`<`T`\>
282
+
283
+ ___
284
+
285
+ #### synchronized
286
+
287
+ ▸ **synchronized**<`T`\>(`lock`, `operation`): `Promise`<`T`\>
288
+
289
+ See [synchronized](#synchronized) for full documentation.
290
+
291
+ ##### Type parameters
292
+
293
+ | Name |
294
+ | :------ |
295
+ | `T` |
296
+
297
+ ##### Parameters
298
+
299
+ | Name | Type |
300
+ | :------ | :------ |
301
+ | `lock` | `unknown` |
302
+ | `operation` | (`previousState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousSettledState`: `undefined` \| [`PromiseState`](#enumspromisestatemd), `previousResult`: `any`) => `Promise`<`T`\> |
303
+
304
+ ##### Returns
305
+
306
+ `Promise`<`T`\>
307
+
308
+ ___
309
+
310
+ #### timeoutReject
311
+
312
+ ▸ **timeoutReject**<`T`, `R`\>(`operation`, `ms`, `rejectReason`): `Promise`<`T`\>
313
+
314
+ See [timeoutReject](#timeoutreject) for full documentation.
315
+
316
+ ##### Type parameters
317
+
318
+ | Name | Type |
319
+ | :------ | :------ |
320
+ | `T` | `never` |
321
+ | `R` | `any` |
322
+
323
+ ##### Parameters
324
+
325
+ | Name | Type |
326
+ | :------ | :------ |
327
+ | `operation` | `Promise`<`T`\> \| () => `Promise`<`T`\> |
328
+ | `ms` | `number` |
329
+ | `rejectReason` | `R` \| `PromiseLike`<`R`\> \| () => `R` \| `PromiseLike`<`R`\> |
330
+
331
+ ##### Returns
332
+
333
+ `Promise`<`T`\>
334
+
335
+ ___
336
+
337
+ #### timeoutResolve
338
+
339
+ ▸ **timeoutResolve**<`T`\>(`operation`, `ms`, `result?`): `Promise`<`T`\>
340
+
341
+ See [timeoutResolve](#timeoutresolve) for full documentation.
342
+
343
+ ##### Type parameters
344
+
345
+ | Name |
346
+ | :------ |
347
+ | `T` |
348
+
349
+ ##### Parameters
350
+
351
+ | Name | Type |
352
+ | :------ | :------ |
353
+ | `operation` | `Promise`<`T`\> \| () => `Promise`<`T`\> |
354
+ | `ms` | `number` |
355
+ | `result?` | `T` \| `PromiseLike`<`T`\> \| () => `T` \| `PromiseLike`<`T`\> |
356
+
357
+ ##### Returns
158
358
 
159
- #### Table of contents
359
+ `Promise`<`T`\>
360
+
361
+ ___
362
+
363
+ #### withRetry
364
+
365
+ ▸ **withRetry**<`Result`, `TError`\>(`operation`, `backoff`, `shouldRetry?`): `Promise`<`Result`\>
366
+
367
+ See [withRetry](#withretry) for full documentation.
368
+
369
+ ##### Type parameters
160
370
 
161
- ##### Constructors
371
+ | Name | Type |
372
+ | :------ | :------ |
373
+ | `Result` | `Result` |
374
+ | `TError` | `any` |
162
375
 
163
- - [constructor](#constructor)
376
+ ##### Parameters
164
377
 
165
- ##### Methods
378
+ | Name | Type |
379
+ | :------ | :------ |
380
+ | `operation` | (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `Promise`<`Result`\> |
381
+ | `backoff` | `number`[] \| (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `undefined` \| `number` |
382
+ | `shouldRetry` | (`previousError`: `undefined` \| `TError`, `previousResult`: `undefined` \| `Result`, `attempt`: `number`) => `boolean` |
383
+
384
+ ##### Returns
385
+
386
+ `Promise`<`Result`\>
166
387
 
167
- - [delayedReject](#delayedreject)
168
- - [delayedResolve](#delayedresolve)
169
- - [inParallel](#inparallel)
170
- - [promiseState](#promisestate)
171
- - [repeat](#repeat)
172
- - [synchronised](#synchronised)
173
- - [synchronized](#synchronized)
174
- - [timeoutReject](#timeoutreject)
175
- - [timeoutResolve](#timeoutresolve)
176
- - [withRetry](#withretry)
388
+ ## Classes
389
+
390
+
391
+ <a name="classespromiseutilsmd"></a>
392
+
393
+ ### Class: PromiseUtils
177
394
 
178
395
  #### Constructors
179
396
 
@@ -228,7 +445,7 @@ Create a Promise that resolves after number of milliseconds specified
228
445
  | Name | Type | Description |
229
446
  | :------ | :------ | :------ |
230
447
  | `ms` | `number` | number of milliseconds after which the created Promise would resolve |
231
- | `result?` | `T` \| `PromiseLike`<`T`\> \| () => `T` \| `PromiseLike`<`T`\> | the result to be resolved for the Promise, or a function that supplies the reuslt. |
448
+ | `result?` | `T` \| `PromiseLike`<`T`\> \| () => `T` \| `PromiseLike`<`T`\> | the result to be resolved for the Promise, or a function that supplies the result. |
232
449
 
233
450
  ###### Returns
234
451
 
@@ -240,23 +457,17 @@ ___
240
457
 
241
458
  ##### inParallel
242
459
 
243
- ▸ `Static` **inParallel**<`Data`, `Result`, `TError`\>(`parallelism`, `jobs`, `operation`): `Promise`<(`Result` \| `TError`)[]\>
460
+ ▸ `Static` **inParallel**<`Data`, `Result`, `TError`\>(`parallelism`, `jobs`, `operation`, `options?`): `Promise`<(`Result` \| `TError`)[]\>
244
461
 
245
462
  Run multiple jobs/operations in parallel.
246
463
 
247
- **`example`**
248
- ```javascript
464
+ By default this function does not throw / reject with error when any of the job/operation fails.
465
+ Operation errors are returned together with operation results in the same returned array.
466
+ That also means this function only returns when all the jobs/operations settle (either resolve or reject).
249
467
 
250
- const topicArns = topics.map(topic => topic.TopicArn!);
251
- await PromiseUtils.inParallel(5, topicArns, async topicArn => {
252
- const topicAttributes = (await sns.getTopicAttributes({ TopicArn: topicArn }).promise()).Attributes!;
253
- const topicDetails = { ...topicAttributes, subscriptions: [] } as any;
254
- if (this.shouldInclude(topicArn)) {
255
- inventory.snsTopicsByArn.set(topicArn, topicDetails);
256
- }
257
- });
468
+ However, if options.abortOnError is true, this function throws / rejects with error when any of the job/operation fails.
469
+ That also means, some of the jobs/operations may not get the chance to be executed if one of them fails.
258
470
 
259
- ```
260
471
  ###### Type parameters
261
472
 
262
473
  | Name | Type | Description |
@@ -270,16 +481,34 @@ await PromiseUtils.inParallel(5, topicArns, async topicArn => {
270
481
  | Name | Type | Description |
271
482
  | :------ | :------ | :------ |
272
483
  | `parallelism` | `number` | how many jobs/operations can be running at the same time |
273
- | `jobs` | `Iterable`<`Data`\> | job data which will be the input to operation function. This function is safe when there are infinite unknown number of elements in the job data. |
484
+ | `jobs` | `Iterable`<`Data`\> | job data which will be the input to operation function. This function is safe when there are infinite unknown number of elements in the job data. |
274
485
  | `operation` | (`job`: `Data`, `index`: `number`) => `Promise`<`Result`\> | the function that turns job data into result asynchronously |
486
+ | `options?` | `Object` | Options for controlling the behavior of this function. |
487
+ | `options.abortOnError` | `boolean` | - |
275
488
 
276
489
  ###### Returns
277
490
 
278
491
  `Promise`<(`Result` \| `TError`)[]\>
279
492
 
280
493
  Promise of void if the operation function does not return a value,
281
- or promise of an array containing results returned from the operation function.
282
- In the array containing results, each element is either the fulfilled result, or the rejected error/reason.
494
+ or promise of an array containing outcomes from the operation function.
495
+ In the returned array containing outcomes, each element is either the fulfilled result, or the rejected error/reason.
496
+
497
+ **`Example`**
498
+
499
+ ```ts
500
+ const attributesAndPossibleErrors = await PromiseUtils.inParallel(5, topicArns, async (topicArn) => {
501
+ const topicAttributes = (await sns.getTopicAttributes({ TopicArn: topicArn }).promise()).Attributes!;
502
+ return topicAttributes;
503
+ });
504
+
505
+ let results: Array<JobResult>;
506
+ try {
507
+ results = await PromiseUtils.inParallel(100, jobs, async (job) => processor.process(job), { abortOnError: true });
508
+ } catch (error) {
509
+ // handle the error
510
+ }
511
+ ```
283
512
 
284
513
  ___
285
514
 
@@ -300,7 +529,7 @@ Please note that the returned value is a Promise, although it resolves immediate
300
529
 
301
530
  `Promise`<[`PromiseState`](#enumspromisestatemd)\>
302
531
 
303
- A Promise that resolves immediately cotaining the state of the input Promise
532
+ A Promise that resolves immediately containing the state of the input Promise
304
533
 
305
534
  ___
306
535
 
@@ -311,17 +540,6 @@ ___
311
540
  Do an operation repeatedly and collect all the results.
312
541
  This function is useful for client side pagination.
313
542
 
314
- **`example`**
315
- ```javascript
316
-
317
- const domainNameObjects = await PromiseUtils.repeat(
318
- pagingParam => apig.getDomainNames({limit: 500, ...pagingParam}).promise(),
319
- esponse => response.position? {position: response.position} : null,
320
- (collection, response) => collection.concat(response.items!),
321
- [] as APIGateway.DomainName[],
322
- );
323
-
324
- ```
325
543
  ###### Type parameters
326
544
 
327
545
  | Name | Description |
@@ -335,7 +553,7 @@ const domainNameObjects = await PromiseUtils.repeat(
335
553
  | Name | Type | Description |
336
554
  | :------ | :------ | :------ |
337
555
  | `operation` | (`parameter`: `Partial`<`Param`\>) => `Promise`<`Result`\> | a function that takes paging parameter as input and outputs a result, normally the operation supports paging |
338
- | `nextParameter` | (`response`: `Result`) => ``null`` \| `Partial`<`Param`\> \| `Promise`<`Partial`<`Param`\>\> | The function for calculating next parameter from the operation result. Normally the parameter controls paging, This function should return null when next invocation of the operation function is not desired. If next invocation is desired, the return value of this function can be a Promise or not a Promise. |
556
+ | `nextParameter` | (`response`: `Result`) => ``null`` \| `Partial`<`Param`\> \| `Promise`<`Partial`<`Param`\>\> | The function for calculating next parameter from the operation result. Normally the parameter controls paging, This function should return null when next invocation of the operation function is not desired. If next invocation is desired, the return value of this function can be a Promise or not a Promise. |
339
557
  | `collect` | (`collection`: `Collection`, `result`: `Result`) => `Collection` | the function for merging operation result into the collection |
340
558
  | `initialCollection` | `Collection` | initial collection which would be the first argument passed into the first invocation of the collect function |
341
559
  | `initialParameter` | `Partial`<`Param`\> | the parameter for the first operation |
@@ -346,13 +564,24 @@ const domainNameObjects = await PromiseUtils.repeat(
346
564
 
347
565
  Promise of collection of all the results returned by the operation function
348
566
 
567
+ **`Example`**
568
+
569
+ ```ts
570
+ const domainNameObjects = await PromiseUtils.repeat(
571
+ pagingParam => apig.getDomainNames({limit: 500, ...pagingParam}).promise(),
572
+ response => response.position? {position: response.position} : null,
573
+ (collection, response) => collection.concat(response.items!),
574
+ [] as APIGateway.DomainName[],
575
+ );
576
+ ```
577
+
349
578
  ___
350
579
 
351
580
  ##### synchronised
352
581
 
353
582
  ▸ `Static` **synchronised**<`T`\>(`lock`, `operation`): `Promise`<`T`\>
354
583
 
355
- This is just another spelling of [PromiseUtils.synchronized](#synchronized).
584
+ This is just another spelling of [synchronized](#synchronized).
356
585
 
357
586
  ###### Type parameters
358
587
 
@@ -410,11 +639,11 @@ ___
410
639
 
411
640
  ▸ `Static` **timeoutReject**<`T`, `R`\>(`operation`, `ms`, `rejectReason`): `Promise`<`T`\>
412
641
 
413
- Apply timeout to a Promise. In case timeout happens, reject with the reason specified.
414
- If timeout does not happen, the resolved result or rejection reason of the original Promise would be the outcome of the Promise returned from this function.
415
- If timeout does not happen and the 'rejectReason' parameter is a function, the function won't be called.
416
- The 'operation' parameter's rejection would not be handled by this function, you may want to handle it outside of this function,
417
- just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
642
+ Applies a timeout to a Promise or a function that returns a Promise.
643
+ If the timeout occurs, rejects with the specified reason.
644
+ If the timeout doesn't occur, the resolved result or rejection reason of the original Promise will be the outcome of the Promise returned from this function.
645
+ If the 'reason' parameter is a function and timeout doesn't occur, the function won't be called.
646
+ The rejection of the 'operation' parameter is not handled by this function, you may want to handle it outside of this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
418
647
 
419
648
  ###### Type parameters
420
649
 
@@ -427,15 +656,15 @@ just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Pro
427
656
 
428
657
  | Name | Type | Description |
429
658
  | :------ | :------ | :------ |
430
- | `operation` | `Promise`<`T`\> | the original Promise for which timeout would be applied |
431
- | `ms` | `number` | number of milliseconds for the timeout |
432
- | `rejectReason` | `R` \| `PromiseLike`<`R`\> \| () => `R` \| `PromiseLike`<`R`\> | the reason of the rejection in case timeout happens, or a function that supplies the reason. |
659
+ | `operation` | `Promise`<`T`\> \| () => `Promise`<`T`\> | The original Promise or a function that returns a Promise for which the timeout will be applied. |
660
+ | `ms` | `number` | The number of milliseconds for the timeout. |
661
+ | `rejectReason` | `R` \| `PromiseLike`<`R`\> \| () => `R` \| `PromiseLike`<`R`\> | The reason to reject with if the timeout occurs, or a function that supplies the reason. |
433
662
 
434
663
  ###### Returns
435
664
 
436
665
  `Promise`<`T`\>
437
666
 
438
- the new Promise that rejects with the specified reason in case timeout happens
667
+ A new Promise that rejects with the specified reason if the timeout occurs.
439
668
 
440
669
  ___
441
670
 
@@ -443,11 +672,11 @@ ___
443
672
 
444
673
  ▸ `Static` **timeoutResolve**<`T`\>(`operation`, `ms`, `result?`): `Promise`<`T`\>
445
674
 
446
- Apply timeout to a Promise. In case timeout happens, resolve to the result specified.
447
- If timeout does not happen, the resolved result or rejection reason of the original Promise would be the outcome of the Promise returned from this function.
448
- If timeout does not happen and the 'result' parameter is a function, the function won't be called.
449
- The 'operation' parameter's rejection would not be handled by this function, you may want to handle it outside of this function,
450
- just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
675
+ Applies a timeout to a Promise or a function that returns a Promise.
676
+ If the timeout occurs, resolves to the specified result.
677
+ If the timeout doesn't occur, the resolved result or rejection reason of the original Promise will be the outcome of the Promise returned from this function.
678
+ If the 'result' parameter is a function and timeout doesn't occur, the function won't be called.
679
+ The rejection of the 'operation' parameter is not handled by this function, you may want to handle it outside of this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
451
680
 
452
681
  ###### Type parameters
453
682
 
@@ -459,15 +688,15 @@ just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Pro
459
688
 
460
689
  | Name | Type | Description |
461
690
  | :------ | :------ | :------ |
462
- | `operation` | `Promise`<`T`\> | the original Promise for which timeout would be applied |
463
- | `ms` | `number` | number of milliseconds for the timeout |
464
- | `result?` | `T` \| `PromiseLike`<`T`\> \| () => `T` \| `PromiseLike`<`T`\> | the result to be resolved in case timeout happens, or a function that supplies the reuslt. |
691
+ | `operation` | `Promise`<`T`\> \| () => `Promise`<`T`\> | The original Promise or a function that returns a Promise for which the timeout will be applied. |
692
+ | `ms` | `number` | The number of milliseconds for the timeout. |
693
+ | `result?` | `T` \| `PromiseLike`<`T`\> \| () => `T` \| `PromiseLike`<`T`\> | The result to be resolved with if the timeout occurs, or a function that supplies the result. |
465
694
 
466
695
  ###### Returns
467
696
 
468
697
  `Promise`<`T`\>
469
698
 
470
- the new Promise that resolves to the specified result in case timeout happens
699
+ A new Promise that resolves to the specified result if the timeout occurs.
471
700
 
472
701
  ___
473
702
 
@@ -477,14 +706,6 @@ ___
477
706
 
478
707
  Do an operation repeatedly until a criteria is met.
479
708
 
480
- **`example`**
481
- ```javascript
482
-
483
- const result = await PromiseUtils.withRetry(() => doSomething(), [100, 200, 300, 500, 800, 1000]);
484
- const result2 = await PromiseUtils.withRetry(() => doSomething(), Array.from({length: 10}, (_v, i) => 1000 * Math.min(FIBONACCI_SEQUENCE[i], 10), err => err.statusCode === 429);
485
- const result3 = await PromiseUtils.withRetry(() => doSomething(), attempt => attempt <= 8 ? 1000 * Math.min(FIBONACCI_SEQUENCE[attempt - 1], 10) : undefined, err => err.statusCode === 429);
486
-
487
- ```
488
709
  ###### Type parameters
489
710
 
490
711
  | Name | Type | Description |
@@ -497,8 +718,8 @@ const result3 = await PromiseUtils.withRetry(() => doSomething(), attempt => att
497
718
  | Name | Type | Description |
498
719
  | :------ | :------ | :------ |
499
720
  | `operation` | (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `Promise`<`Result`\> | a function that outputs a Promise result, normally the operation does not use its arguments |
500
- | `backoff` | `number`[] \| (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `undefined` \| `number` | Array of retry backoff periods (unit: milliseconds) or function for calculating them. If retry is desired, before making next call to the operation the desired backoff period would be waited. If the array runs out of elements or the function returns `undefined` or either the array or the function returns a negative number, there would be no further call to the operation. The `attempt` argument passed into backoff function starts from 1 because the function is called right after the first attempt and before the first retry. |
501
- | `shouldRetry` | (`previousError`: `undefined` \| `TError`, `previousResult`: `undefined` \| `Result`, `attempt`: `number`) => `boolean` | Predicate function for deciding whether another call to the operation should happen. If this argument is not defined, retry would happen whenever the operation rejects with an error. `shouldRetry` would be evaluated before `backoff`. The `attempt` argument passed into shouldRetry function starts from 1. |
721
+ | `backoff` | `number`[] \| (`attempt`: `number`, `previousResult`: `undefined` \| `Result`, `previousError`: `undefined` \| `TError`) => `undefined` \| `number` | Array of retry backoff periods (unit: milliseconds) or function for calculating them. If retry is desired, before making next call to the operation the desired backoff period would be waited. If the array runs out of elements or the function returns `undefined` or either the array or the function returns a negative number, there would be no further call to the operation. The `attempt` argument passed into backoff function starts from 1 because the function is called right after the first attempt and before the first retry. |
722
+ | `shouldRetry` | (`previousError`: `undefined` \| `TError`, `previousResult`: `undefined` \| `Result`, `attempt`: `number`) => `boolean` | Predicate function for deciding whether another call to the operation should happen. If this argument is not defined, retry would happen whenever the operation rejects with an error. `shouldRetry` would be evaluated before `backoff`. The `attempt` argument passed into shouldRetry function starts from 1. |
502
723
 
503
724
  ###### Returns
504
725
 
@@ -506,40 +727,38 @@ const result3 = await PromiseUtils.withRetry(() => doSomething(), attempt => att
506
727
 
507
728
  Promise of the operation result potentially with retries already applied
508
729
 
730
+ **`Example`**
731
+
732
+ ```ts
733
+ const result = await PromiseUtils.withRetry(() => doSomething(), [100, 200, 300, 500, 800, 1000]);
734
+ const result2 = await PromiseUtils.withRetry(() => doSomething(), Array.from({length: 10}, (_v, i) => 1000 * Math.min(FIBONACCI_SEQUENCE[i], 10), err => err.statusCode === 429);
735
+ const result3 = await PromiseUtils.withRetry(() => doSomething(), attempt => attempt <= 8 ? 1000 * Math.min(FIBONACCI_SEQUENCE[attempt - 1], 10) : undefined, err => err.statusCode === 429);
736
+ ```
737
+
509
738
  ## Enums
510
739
 
511
740
 
512
741
  <a name="enumspromisestatemd"></a>
513
742
 
514
- [@handy-common-utils/promise-utils](#readmemd) / PromiseState
515
-
516
743
  ### Enumeration: PromiseState
517
744
 
518
745
  The state of a Promise can only be one of: Pending, Fulfilled, and Rejected.
519
746
 
520
- #### Table of contents
521
-
522
- ##### Enumeration members
523
-
524
- - [Fulfilled](#fulfilled)
525
- - [Pending](#pending)
526
- - [Rejected](#rejected)
527
-
528
- #### Enumeration members
747
+ #### Enumeration Members
529
748
 
530
749
  ##### Fulfilled
531
750
 
532
- • **Fulfilled** = `"Fulfilled"`
751
+ • **Fulfilled** = ``"Fulfilled"``
533
752
 
534
753
  ___
535
754
 
536
755
  ##### Pending
537
756
 
538
- • **Pending** = `"Pending"`
757
+ • **Pending** = ``"Pending"``
539
758
 
540
759
  ___
541
760
 
542
761
  ##### Rejected
543
762
 
544
- • **Rejected** = `"Rejected"`
763
+ • **Rejected** = ``"Rejected"``
545
764
  <!-- API end -->
@@ -38,7 +38,7 @@ export declare abstract class PromiseUtils {
38
38
  * @example
39
39
  * const domainNameObjects = await PromiseUtils.repeat(
40
40
  * pagingParam => apig.getDomainNames({limit: 500, ...pagingParam}).promise(),
41
- * esponse => response.position? {position: response.position} : null,
41
+ * response => response.position? {position: response.position} : null,
42
42
  * (collection, response) => collection.concat(response.items!),
43
43
  * [] as APIGateway.DomainName[],
44
44
  * );
@@ -86,16 +86,26 @@ export declare abstract class PromiseUtils {
86
86
  /**
87
87
  * Run multiple jobs/operations in parallel.
88
88
  *
89
+ * By default this function does not throw / reject with error when any of the job/operation fails.
90
+ * Operation errors are returned together with operation results in the same returned array.
91
+ * That also means this function only returns when all the jobs/operations settle (either resolve or reject).
92
+ *
93
+ * However, if options.abortOnError is true, this function throws / rejects with error when any of the job/operation fails.
94
+ * That also means, some of the jobs/operations may not get the chance to be executed if one of them fails.
95
+ *
89
96
  * @example
90
- * const topicArns = topics.map(topic => topic.TopicArn!);
91
- * await PromiseUtils.inParallel(5, topicArns, async topicArn => {
97
+ * const attributesAndPossibleErrors = await PromiseUtils.inParallel(5, topicArns, async (topicArn) => {
92
98
  * const topicAttributes = (await sns.getTopicAttributes({ TopicArn: topicArn }).promise()).Attributes!;
93
- * const topicDetails = { ...topicAttributes, subscriptions: [] } as any;
94
- * if (this.shouldInclude(topicArn)) {
95
- * inventory.snsTopicsByArn.set(topicArn, topicDetails);
96
- * }
99
+ * return topicAttributes;
97
100
  * });
98
101
  *
102
+ * let results: Array<JobResult>;
103
+ * try {
104
+ * results = await PromiseUtils.inParallel(100, jobs, async (job) => processor.process(job), { abortOnError: true });
105
+ * } catch (error) {
106
+ * // handle the error
107
+ * }
108
+ *
99
109
  * @template Data Type of the job data, usually it would be an Array
100
110
  * @template Result Type of the return value of the operation function
101
111
  *
@@ -103,15 +113,18 @@ export declare abstract class PromiseUtils {
103
113
  * @param jobs job data which will be the input to operation function.
104
114
  * This function is safe when there are infinite unknown number of elements in the job data.
105
115
  * @param operation the function that turns job data into result asynchronously
116
+ * @param options Options for controlling the behavior of this function.
106
117
  * @returns Promise of void if the operation function does not return a value,
107
- * or promise of an array containing results returned from the operation function.
108
- * In the array containing results, each element is either the fulfilled result, or the rejected error/reason.
118
+ * or promise of an array containing outcomes from the operation function.
119
+ * In the returned array containing outcomes, each element is either the fulfilled result, or the rejected error/reason.
109
120
  */
110
- static inParallel<Data, Result, TError = Result>(parallelism: number, jobs: Iterable<Data>, operation: (job: Data, index: number) => Promise<Result>): Promise<Array<Result | TError>>;
121
+ static inParallel<Data, Result, TError = Result>(parallelism: number, jobs: Iterable<Data>, operation: (job: Data, index: number) => Promise<Result>, options?: {
122
+ abortOnError: boolean;
123
+ }): Promise<Array<Result | TError>>;
111
124
  /**
112
125
  * Create a Promise that resolves after number of milliseconds specified
113
126
  * @param ms number of milliseconds after which the created Promise would resolve
114
- * @param result the result to be resolved for the Promise, or a function that supplies the reuslt.
127
+ * @param result the result to be resolved for the Promise, or a function that supplies the result.
115
128
  * @returns the new Promise created
116
129
  */
117
130
  static delayedResolve<T>(ms: number, result?: T | PromiseLike<T> | (() => (T | PromiseLike<T>))): Promise<T>;
@@ -124,34 +137,36 @@ export declare abstract class PromiseUtils {
124
137
  */
125
138
  static delayedReject<T = never, R = any>(ms: number, reason: R | PromiseLike<R> | (() => R | PromiseLike<R>)): Promise<T>;
126
139
  /**
127
- * Apply timeout to a Promise. In case timeout happens, resolve to the result specified.
128
- * If timeout does not happen, the resolved result or rejection reason of the original Promise would be the outcome of the Promise returned from this function.
129
- * If timeout does not happen and the 'result' parameter is a function, the function won't be called.
130
- * The 'operation' parameter's rejection would not be handled by this function, you may want to handle it outside of this function,
131
- * just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
132
- * @param operation the original Promise for which timeout would be applied
133
- * @param ms number of milliseconds for the timeout
134
- * @param result the result to be resolved in case timeout happens, or a function that supplies the reuslt.
135
- * @return the new Promise that resolves to the specified result in case timeout happens
140
+ * Applies a timeout to a Promise or a function that returns a Promise.
141
+ * If the timeout occurs, resolves to the specified result.
142
+ * If the timeout doesn't occur, the resolved result or rejection reason of the original Promise will be the outcome of the Promise returned from this function.
143
+ * If the 'result' parameter is a function and timeout doesn't occur, the function won't be called.
144
+ * The rejection of the 'operation' parameter is not handled by this function, you may want to handle it outside of this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
145
+ *
146
+ * @param operation The original Promise or a function that returns a Promise for which the timeout will be applied.
147
+ * @param ms The number of milliseconds for the timeout.
148
+ * @param result The result to be resolved with if the timeout occurs, or a function that supplies the result.
149
+ * @return A new Promise that resolves to the specified result if the timeout occurs.
136
150
  */
137
- static timeoutResolve<T>(operation: Promise<T>, ms: number, result?: T | PromiseLike<T> | (() => (T | PromiseLike<T>)) | undefined): Promise<T>;
151
+ static timeoutResolve<T>(operation: Promise<T> | (() => Promise<T>), ms: number, result?: T | PromiseLike<T> | (() => (T | PromiseLike<T>)) | undefined): Promise<T>;
138
152
  /**
139
- * Apply timeout to a Promise. In case timeout happens, reject with the reason specified.
140
- * If timeout does not happen, the resolved result or rejection reason of the original Promise would be the outcome of the Promise returned from this function.
141
- * If timeout does not happen and the 'rejectReason' parameter is a function, the function won't be called.
142
- * The 'operation' parameter's rejection would not be handled by this function, you may want to handle it outside of this function,
143
- * just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
144
- * @param operation the original Promise for which timeout would be applied
145
- * @param ms number of milliseconds for the timeout
146
- * @param rejectReason the reason of the rejection in case timeout happens, or a function that supplies the reason.
147
- * @return the new Promise that rejects with the specified reason in case timeout happens
153
+ * Applies a timeout to a Promise or a function that returns a Promise.
154
+ * If the timeout occurs, rejects with the specified reason.
155
+ * If the timeout doesn't occur, the resolved result or rejection reason of the original Promise will be the outcome of the Promise returned from this function.
156
+ * If the 'reason' parameter is a function and timeout doesn't occur, the function won't be called.
157
+ * The rejection of the 'operation' parameter is not handled by this function, you may want to handle it outside of this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
158
+ *
159
+ * @param operation The original Promise or a function that returns a Promise for which the timeout will be applied.
160
+ * @param ms The number of milliseconds for the timeout.
161
+ * @param rejectReason The reason to reject with if the timeout occurs, or a function that supplies the reason.
162
+ * @return A new Promise that rejects with the specified reason if the timeout occurs.
148
163
  */
149
- static timeoutReject<T = never, R = any>(operation: Promise<T>, ms: number, rejectReason: R | PromiseLike<R> | (() => R | PromiseLike<R>)): Promise<T>;
164
+ static timeoutReject<T = never, R = any>(operation: Promise<T> | (() => Promise<T>), ms: number, rejectReason: R | PromiseLike<R> | (() => R | PromiseLike<R>)): Promise<T>;
150
165
  /**
151
166
  * Get the state of the Promise.
152
167
  * Please note that the returned value is a Promise, although it resolves immediately.
153
168
  * @param p the Promise for which we would like to know its state
154
- * @return A Promise that resolves immediately cotaining the state of the input Promise
169
+ * @return A Promise that resolves immediately containing the state of the input Promise
155
170
  */
156
171
  static promiseState(p: Promise<any>): Promise<PromiseState>;
157
172
  private static synchronizationLocks;
@@ -1 +1 @@
1
- {"version":3,"file":"promise-utils.d.ts","sourceRoot":"","sources":["../src/promise-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,UAAkJ,CAAC;AAElL;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,UAA6K,CAAC;AAE/M;;GAEG;AACH,oBAAY,YAAY;IACtB,OAAO,YAAY;IACnB,SAAS,cAAc;IACvB,QAAQ,aAAa;CACtB;AAED,8BAAsB,YAAY;IAChC;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;WACU,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,UAAU,EAC3C,SAAS,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,EACzD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,EACpF,OAAO,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,KAAK,UAAU,EAC/D,iBAAiB,EAAE,UAAU,EAC7B,gBAAgB,GAAE,OAAO,CAAC,KAAK,CAAM,GACpC,OAAO,CAAC,UAAU,CAAC;IAetB;;;;;;;;;;;;;;;;;;;;;;OAsBG;WACU,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,EACzC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAC,SAAS,EAAE,aAAa,EAAE,MAAM,GAAC,SAAS,KAAK,OAAO,CAAC,MAAM,CAAC,EAClH,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAC,SAAS,EAAE,aAAa,EAAE,MAAM,GAAC,SAAS,KAAK,MAAM,GAAC,SAAS,CAAC,EACnI,WAAW,GAAE,CAAC,aAAa,EAAE,MAAM,GAAC,SAAS,EAAE,cAAc,EAAE,MAAM,GAAC,SAAS,EAAE,OAAO,EAAE,MAAM,KAAK,OAAmF,GACvL,OAAO,CAAC,MAAM,CAAC;IAyBlB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;WACU,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EACnD,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EACpB,SAAS,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GACvD,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAwBlC;;;;;OAKG;IACH,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAO5G;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAQvH;;;;;;;;;;OAUG;IACH,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC;IAa/I;;;;;;;;;;OAUG;IACH,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAapJ;;;;;OAKG;IACH,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC;IAM3D,OAAO,CAAC,MAAM,CAAC,oBAAoB,CAAgC;IAEnE;;;;;;;;;OASG;WACU,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,aAAa,EAAE,YAAY,GAAG,SAAS,EAAE,oBAAoB,EAAE,YAAY,GAAG,SAAS,EAAE,cAAc,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAwBhM;;;;;OAKG;WACU,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,aAAa,EAAE,YAAY,GAAG,SAAS,EAAE,oBAAoB,EAAE,YAAY,GAAG,SAAS,EAAE,cAAc,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAGjM;AAED;;GAEG;AACH,eAAO,MAAM,MAAM,4BAAsB,CAAC;AAC1C;;GAEG;AACH,eAAO,MAAM,SAAS,+BAAyB,CAAC;AAChD;;GAEG;AACH,eAAO,MAAM,UAAU,gCAA0B,CAAC;AAClD;;GAEG;AACH,eAAO,MAAM,cAAc,oCAA8B,CAAC;AAC1D;;GAEG;AACH,eAAO,MAAM,aAAa,mCAA6B,CAAC;AACxD;;GAEG;AACH,eAAO,MAAM,cAAc,oCAA8B,CAAC;AAC1D;;GAEG;AACH,eAAO,MAAM,aAAa,mCAA6B,CAAC;AACxD;;GAEG;AACH,eAAO,MAAM,YAAY,kCAA4B,CAAC;AACtD;;GAEG;AACH,eAAO,MAAM,YAAY,kCAA4B,CAAC;AACtD;;GAEG;AACH,eAAO,MAAM,YAAY,kCAA4B,CAAC"}
1
+ {"version":3,"file":"promise-utils.d.ts","sourceRoot":"","sources":["../src/promise-utils.ts"],"names":[],"mappings":"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"}
@@ -33,7 +33,7 @@ var PromiseState;
33
33
  PromiseState["Pending"] = "Pending";
34
34
  PromiseState["Fulfilled"] = "Fulfilled";
35
35
  PromiseState["Rejected"] = "Rejected";
36
- })(PromiseState = exports.PromiseState || (exports.PromiseState = {}));
36
+ })(PromiseState || (exports.PromiseState = PromiseState = {}));
37
37
  class PromiseUtils {
38
38
  /**
39
39
  * Do an operation repeatedly and collect all the results.
@@ -42,7 +42,7 @@ class PromiseUtils {
42
42
  * @example
43
43
  * const domainNameObjects = await PromiseUtils.repeat(
44
44
  * pagingParam => apig.getDomainNames({limit: 500, ...pagingParam}).promise(),
45
- * esponse => response.position? {position: response.position} : null,
45
+ * response => response.position? {position: response.position} : null,
46
46
  * (collection, response) => collection.concat(response.items!),
47
47
  * [] as APIGateway.DomainName[],
48
48
  * );
@@ -120,16 +120,26 @@ class PromiseUtils {
120
120
  /**
121
121
  * Run multiple jobs/operations in parallel.
122
122
  *
123
+ * By default this function does not throw / reject with error when any of the job/operation fails.
124
+ * Operation errors are returned together with operation results in the same returned array.
125
+ * That also means this function only returns when all the jobs/operations settle (either resolve or reject).
126
+ *
127
+ * However, if options.abortOnError is true, this function throws / rejects with error when any of the job/operation fails.
128
+ * That also means, some of the jobs/operations may not get the chance to be executed if one of them fails.
129
+ *
123
130
  * @example
124
- * const topicArns = topics.map(topic => topic.TopicArn!);
125
- * await PromiseUtils.inParallel(5, topicArns, async topicArn => {
131
+ * const attributesAndPossibleErrors = await PromiseUtils.inParallel(5, topicArns, async (topicArn) => {
126
132
  * const topicAttributes = (await sns.getTopicAttributes({ TopicArn: topicArn }).promise()).Attributes!;
127
- * const topicDetails = { ...topicAttributes, subscriptions: [] } as any;
128
- * if (this.shouldInclude(topicArn)) {
129
- * inventory.snsTopicsByArn.set(topicArn, topicDetails);
130
- * }
133
+ * return topicAttributes;
131
134
  * });
132
135
  *
136
+ * let results: Array<JobResult>;
137
+ * try {
138
+ * results = await PromiseUtils.inParallel(100, jobs, async (job) => processor.process(job), { abortOnError: true });
139
+ * } catch (error) {
140
+ * // handle the error
141
+ * }
142
+ *
133
143
  * @template Data Type of the job data, usually it would be an Array
134
144
  * @template Result Type of the return value of the operation function
135
145
  *
@@ -137,11 +147,12 @@ class PromiseUtils {
137
147
  * @param jobs job data which will be the input to operation function.
138
148
  * This function is safe when there are infinite unknown number of elements in the job data.
139
149
  * @param operation the function that turns job data into result asynchronously
150
+ * @param options Options for controlling the behavior of this function.
140
151
  * @returns Promise of void if the operation function does not return a value,
141
- * or promise of an array containing results returned from the operation function.
142
- * In the array containing results, each element is either the fulfilled result, or the rejected error/reason.
152
+ * or promise of an array containing outcomes from the operation function.
153
+ * In the returned array containing outcomes, each element is either the fulfilled result, or the rejected error/reason.
143
154
  */
144
- static async inParallel(parallelism, jobs, operation) {
155
+ static async inParallel(parallelism, jobs, operation, options) {
145
156
  if (parallelism < 1) {
146
157
  parallelism = 1;
147
158
  }
@@ -158,7 +169,7 @@ class PromiseUtils {
158
169
  const job = iteratorResult.value;
159
170
  const jobIndex = index++;
160
171
  const jobResultPromise = operation(job, jobIndex);
161
- jobResults[jobIndex] = await jobResultPromise.catch(error => error);
172
+ jobResults[jobIndex] = (options === null || options === void 0 ? void 0 : options.abortOnError) ? await jobResultPromise : await jobResultPromise.catch(error => error);
162
173
  }
163
174
  });
164
175
  await Promise.all(promises);
@@ -167,7 +178,7 @@ class PromiseUtils {
167
178
  /**
168
179
  * Create a Promise that resolves after number of milliseconds specified
169
180
  * @param ms number of milliseconds after which the created Promise would resolve
170
- * @param result the result to be resolved for the Promise, or a function that supplies the reuslt.
181
+ * @param result the result to be resolved for the Promise, or a function that supplies the result.
171
182
  * @returns the new Promise created
172
183
  */
173
184
  static delayedResolve(ms, result) {
@@ -189,40 +200,44 @@ class PromiseUtils {
189
200
  }, ms));
190
201
  }
191
202
  /**
192
- * Apply timeout to a Promise. In case timeout happens, resolve to the result specified.
193
- * If timeout does not happen, the resolved result or rejection reason of the original Promise would be the outcome of the Promise returned from this function.
194
- * If timeout does not happen and the 'result' parameter is a function, the function won't be called.
195
- * The 'operation' parameter's rejection would not be handled by this function, you may want to handle it outside of this function,
196
- * just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
197
- * @param operation the original Promise for which timeout would be applied
198
- * @param ms number of milliseconds for the timeout
199
- * @param result the result to be resolved in case timeout happens, or a function that supplies the reuslt.
200
- * @return the new Promise that resolves to the specified result in case timeout happens
203
+ * Applies a timeout to a Promise or a function that returns a Promise.
204
+ * If the timeout occurs, resolves to the specified result.
205
+ * If the timeout doesn't occur, the resolved result or rejection reason of the original Promise will be the outcome of the Promise returned from this function.
206
+ * If the 'result' parameter is a function and timeout doesn't occur, the function won't be called.
207
+ * The rejection of the 'operation' parameter is not handled by this function, you may want to handle it outside of this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
208
+ *
209
+ * @param operation The original Promise or a function that returns a Promise for which the timeout will be applied.
210
+ * @param ms The number of milliseconds for the timeout.
211
+ * @param result The result to be resolved with if the timeout occurs, or a function that supplies the result.
212
+ * @return A new Promise that resolves to the specified result if the timeout occurs.
201
213
  */
202
214
  static timeoutResolve(operation, ms, result) {
215
+ const promise = typeof operation === 'function' ? operation() : operation;
203
216
  return Promise.race([
204
- operation,
205
- PromiseUtils.delayedResolve(ms, () => PromiseUtils.promiseState(operation)
217
+ promise,
218
+ PromiseUtils.delayedResolve(ms, () => PromiseUtils.promiseState(promise)
206
219
  .then(state => state === PromiseState.Pending ?
207
220
  (typeof result === 'function' ? result() : result) :
208
221
  {})),
209
222
  ]);
210
223
  }
211
224
  /**
212
- * Apply timeout to a Promise. In case timeout happens, reject with the reason specified.
213
- * If timeout does not happen, the resolved result or rejection reason of the original Promise would be the outcome of the Promise returned from this function.
214
- * If timeout does not happen and the 'rejectReason' parameter is a function, the function won't be called.
215
- * The 'operation' parameter's rejection would not be handled by this function, you may want to handle it outside of this function,
216
- * just for avoiding warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
217
- * @param operation the original Promise for which timeout would be applied
218
- * @param ms number of milliseconds for the timeout
219
- * @param rejectReason the reason of the rejection in case timeout happens, or a function that supplies the reason.
220
- * @return the new Promise that rejects with the specified reason in case timeout happens
225
+ * Applies a timeout to a Promise or a function that returns a Promise.
226
+ * If the timeout occurs, rejects with the specified reason.
227
+ * If the timeout doesn't occur, the resolved result or rejection reason of the original Promise will be the outcome of the Promise returned from this function.
228
+ * If the 'reason' parameter is a function and timeout doesn't occur, the function won't be called.
229
+ * The rejection of the 'operation' parameter is not handled by this function, you may want to handle it outside of this function to avoid warnings like "(node:4330) PromiseRejectionHandledWarning: Promise rejection was handled asynchronously".
230
+ *
231
+ * @param operation The original Promise or a function that returns a Promise for which the timeout will be applied.
232
+ * @param ms The number of milliseconds for the timeout.
233
+ * @param rejectReason The reason to reject with if the timeout occurs, or a function that supplies the reason.
234
+ * @return A new Promise that rejects with the specified reason if the timeout occurs.
221
235
  */
222
236
  static timeoutReject(operation, ms, rejectReason) {
237
+ const promise = typeof operation === 'function' ? operation() : operation;
223
238
  return Promise.race([
224
- operation,
225
- PromiseUtils.delayedReject(ms, () => PromiseUtils.promiseState(operation)
239
+ promise,
240
+ PromiseUtils.delayedReject(ms, () => PromiseUtils.promiseState(promise)
226
241
  .then(state => state === PromiseState.Pending ?
227
242
  (typeof rejectReason === 'function' ? rejectReason() : rejectReason) :
228
243
  {})),
@@ -232,7 +247,7 @@ class PromiseUtils {
232
247
  * Get the state of the Promise.
233
248
  * Please note that the returned value is a Promise, although it resolves immediately.
234
249
  * @param p the Promise for which we would like to know its state
235
- * @return A Promise that resolves immediately cotaining the state of the input Promise
250
+ * @return A Promise that resolves immediately containing the state of the input Promise
236
251
  */
237
252
  static promiseState(p) {
238
253
  const t = {};
@@ -257,16 +272,19 @@ class PromiseUtils {
257
272
  previousState = await PromiseUtils.promiseState(previousResultPromise);
258
273
  }
259
274
  switch (previousState) {
260
- case PromiseState.Pending: // concurrency
275
+ case PromiseState.Pending: { // concurrency
261
276
  resultPromise = previousResultPromise.then(result => operation(PromiseState.Pending, PromiseState.Fulfilled, result), error => operation(PromiseState.Pending, PromiseState.Rejected, error));
262
277
  break;
263
- case undefined: // no concurrency and no history
278
+ }
279
+ case undefined: { // no concurrency and no history
264
280
  // eslint-disable-next-line unicorn/no-useless-undefined
265
281
  resultPromise = operation(undefined, undefined, undefined);
266
282
  break;
267
- default: // no concurrency but with history
283
+ }
284
+ default: { // no concurrency but with history
268
285
  resultPromise = operation(previousState, previousState, await previousResultPromise.catch(error => error));
269
286
  break;
287
+ }
270
288
  }
271
289
  PromiseUtils.synchronizationLocks.set(lock, resultPromise);
272
290
  return resultPromise;
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@handy-common-utils/promise-utils",
3
- "version": "1.2.7",
3
+ "version": "1.4.0",
4
4
  "description": "Promise related utilities",
5
5
  "scripts": {
6
6
  "pretest": "eslint . --ext .ts",
7
7
  "test": "nyc mocha",
8
8
  "prepare": "shx rm -rf dist && tsc && es-check",
9
- "preversion": "generate-api-docs-and-update-readme && replace-in-file README.md '[^#]### Functions[\\s\\S]*?## Classes' '## Classes' && git add README.md"
9
+ "preversion": "generate-api-docs-and-update-readme && git add README.md"
10
10
  },
11
11
  "files": [
12
12
  "package.json",
@@ -16,11 +16,8 @@
16
16
  "types": "dist/promise-utils.d.ts",
17
17
  "bin": {},
18
18
  "devDependencies": {
19
- "@handy-common-utils/dev-dependencies": "^1.0.31",
20
- "@types/chai-as-promised": "^7.1.3",
21
- "chai-as-promised": "^7.1.1",
22
- "es-check": "^5.2.3",
23
- "eslint": "^7.32.0"
19
+ "@handy-common-utils/dev-dependencies-mocha": "^1.3.1",
20
+ "@types/node": "^18.17.1"
24
21
  },
25
22
  "publishConfig": {
26
23
  "access": "public"
@@ -34,10 +31,18 @@
34
31
  "url": "https://github.com/handy-common-utils/promise-utils/issues"
35
32
  },
36
33
  "keywords": [
37
- "prmomise",
34
+ "promise",
38
35
  "utils",
36
+ "retry",
37
+ "delay",
38
+ "resolve",
39
+ "reject",
39
40
  "utilities"
40
41
  ],
41
42
  "author": "James Hu",
42
- "license": "Apache-2.0"
43
+ "license": "Apache-2.0",
44
+ "volta": {
45
+ "node": "18.17.0",
46
+ "npm": "9.6.7"
47
+ }
43
48
  }