@superutils/promise 1.0.3 → 1.0.6
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/dist/index.d.ts +215 -111
- package/dist/index.js +80 -67
- package/package.json +5 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _superutils_core from '@superutils/core';
|
|
2
|
-
import { ValueOrPromise, TimeoutId,
|
|
2
|
+
import { ValueOrPromise, TimeoutId, PositiveNumber, ThrottleOptions, DeferredOptions } from '@superutils/core';
|
|
3
3
|
|
|
4
4
|
interface IPromisE<T = unknown> extends Promise<T> {
|
|
5
5
|
/** 0: pending, 1: resolved, 2: rejected */
|
|
@@ -77,25 +77,32 @@ type OnEarlyFinalize<T> = <TResolved extends boolean, TValue = TResolved extends
|
|
|
77
77
|
type PromiseParams<T = unknown> = ConstructorParameters<typeof Promise<T>>;
|
|
78
78
|
|
|
79
79
|
/** Return type of `PromisE.deferred()` */
|
|
80
|
-
type
|
|
81
|
-
type
|
|
82
|
-
|
|
83
|
-
|
|
80
|
+
type DeferredAsyncCallback<TArgs extends unknown[] | [] = []> = <TResult = unknown>(promise: Promise<TResult> | ((...args: TArgs) => Promise<TResult>)) => IPromisE<TResult>;
|
|
81
|
+
type DeferredAsyncGetPromise<T> = <TResult = T>() => Promise<TResult>;
|
|
82
|
+
/** Default options used by `PromisE.deferred` and related functions */
|
|
83
|
+
type DeferredAsyncDefaults = Pick<Required<DeferredAsyncOptions>, 'delayMs' | 'resolveError' | 'resolveIgnored'>;
|
|
84
|
+
/** Options for `PromisE.deferred` and other related functions */
|
|
85
|
+
type DeferredAsyncOptions<ThisArg = unknown, DelayMs extends number = number> = {
|
|
86
|
+
/**
|
|
87
|
+
* Delay in milliseconds, used for `debounce` and `throttle` modes.
|
|
88
|
+
*
|
|
89
|
+
* Default: `100`
|
|
90
|
+
*/
|
|
84
91
|
/** Callback invoked whenever promise/function throws error */
|
|
85
|
-
onError?: (err: unknown) => ValueOrPromise<unknown>;
|
|
92
|
+
onError?: (this: ThisArg, err: unknown) => ValueOrPromise<unknown>;
|
|
86
93
|
/**
|
|
87
94
|
* Whenever a promise/function is ignored when in debource/throttle mode, `onIgnored` wil be invoked.
|
|
88
95
|
* The promise/function will not be invoked, unless it's manually invoked using the `ignored` function.
|
|
89
96
|
* Use for debugging or logging purposes.
|
|
90
97
|
*/
|
|
91
|
-
onIgnore?: (
|
|
98
|
+
onIgnore?: (this: ThisArg, ignored: DeferredAsyncGetPromise<unknown>) => ValueOrPromise<unknown>;
|
|
92
99
|
/**
|
|
93
100
|
* Whenever a promise/function is executed successfully `onResult` will be called.
|
|
94
101
|
* Those that are ignored but resolve with last will not cause `onResult` to be invoked.
|
|
95
102
|
*
|
|
96
103
|
* Result can be `undefined` if `ResolveIgnored.WITH_UNDEFINED` is used.
|
|
97
104
|
*/
|
|
98
|
-
onResult?: (result?:
|
|
105
|
+
onResult?: (this: ThisArg, result?: any) => ValueOrPromise<unknown>;
|
|
99
106
|
/**
|
|
100
107
|
* Indicates what to do when a promise in the queue is ignored.
|
|
101
108
|
* See {@link ResolveIgnored} for available options.
|
|
@@ -106,16 +113,18 @@ type DeferredOptions<ThisArg = unknown> = {
|
|
|
106
113
|
* See {@link ResolveError} for available options.
|
|
107
114
|
*/
|
|
108
115
|
resolveError?: ResolveError;
|
|
109
|
-
/**
|
|
110
|
-
|
|
116
|
+
/** The value to be used as "thisArg" whenever any of the callbacks are invoked */
|
|
117
|
+
thisArg?: ThisArg;
|
|
111
118
|
} & (({
|
|
112
|
-
|
|
119
|
+
/** Throttle duration in milliseconds */
|
|
120
|
+
delayMs?: PositiveNumber<DelayMs>;
|
|
113
121
|
throttle: true;
|
|
114
|
-
} &
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
122
|
+
} & Omit<ThrottleOptions, 'onError' | 'ThisArg' | 'tid'>) | ({
|
|
123
|
+
/** Debounce/deferred duration in milliseconds */
|
|
124
|
+
delayMs?: PositiveNumber<DelayMs>;
|
|
125
|
+
throttle?: false | undefined;
|
|
126
|
+
} & Omit<DeferredOptions, 'onError' | 'ThisArg' | 'tid'>));
|
|
127
|
+
/** Determines what to do when deferred promise/function fails */
|
|
119
128
|
declare enum ResolveError {
|
|
120
129
|
/** Neither resolve nor reject the failed */
|
|
121
130
|
NEVER = "NEVER",
|
|
@@ -126,7 +135,10 @@ declare enum ResolveError {
|
|
|
126
135
|
/** Resolve with undefined */
|
|
127
136
|
WITH_UNDEFINED = "RESOLVE_UNDEFINED"
|
|
128
137
|
}
|
|
129
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Determines what to do when a promise/callback is ignored, either because of being
|
|
140
|
+
* deferred, throttled or another been prioritized.
|
|
141
|
+
*/
|
|
130
142
|
declare enum ResolveIgnored {
|
|
131
143
|
/** Never resolve ignored promises. Caution: make sure this doesn't cause any memory leaks. */
|
|
132
144
|
NEVER = "NEVER",
|
|
@@ -136,22 +148,6 @@ declare enum ResolveIgnored {
|
|
|
136
148
|
WITH_UNDEFINED = "WITH_UNDEFINED"
|
|
137
149
|
}
|
|
138
150
|
|
|
139
|
-
/** Global configuration */
|
|
140
|
-
declare const config: {
|
|
141
|
-
/** Default value for `options` used by `PromisE.*deferred*` functions */
|
|
142
|
-
deferOptions: DeferredOptions;
|
|
143
|
-
delayTimeoutMsg: string;
|
|
144
|
-
retryOptions: {
|
|
145
|
-
retry: number;
|
|
146
|
-
retryBackOff: "exponential";
|
|
147
|
-
retryDelay: number;
|
|
148
|
-
retryDelayJitter: true;
|
|
149
|
-
retryDelayJitterMax: number;
|
|
150
|
-
retryIf: null;
|
|
151
|
-
};
|
|
152
|
-
};
|
|
153
|
-
type Config = typeof config;
|
|
154
|
-
|
|
155
151
|
/** Options for automatic retry mechanism */
|
|
156
152
|
type RetryOptions<T = unknown> = {
|
|
157
153
|
/**
|
|
@@ -188,7 +184,7 @@ type RetryOptions<T = unknown> = {
|
|
|
188
184
|
* Additional condition/function to be used to determine whether function should be retried.
|
|
189
185
|
* `retryIf` will only be executed when function execution is successful.
|
|
190
186
|
*/
|
|
191
|
-
retryIf?: null | ((prevResult: T | undefined, retryCount: number
|
|
187
|
+
retryIf?: null | ((prevResult: T | undefined, retryCount: number) => boolean | Promise<boolean>);
|
|
192
188
|
};
|
|
193
189
|
|
|
194
190
|
declare class PromisEBase<T = unknown> extends Promise<T> implements IPromisE<T> {
|
|
@@ -297,7 +293,38 @@ type TimeoutOptions<Func extends string = 'all'> = {
|
|
|
297
293
|
* @function PromisE.deferred
|
|
298
294
|
* The adaptation of the `deferred()` function tailored for Promises.
|
|
299
295
|
*
|
|
300
|
-
*
|
|
296
|
+
*
|
|
297
|
+
* # Notes
|
|
298
|
+
*
|
|
299
|
+
* - A "request" simply means invokation of the returned callback function
|
|
300
|
+
* - By "handled" it means a "request" will be resolved or rejected.
|
|
301
|
+
* - `PromisE.deferred` is to be used with promises/functions.
|
|
302
|
+
* `PromisE.deferredCallback` is for use with callback functions.
|
|
303
|
+
* - There is no specific time delay.
|
|
304
|
+
* - If a request takes longer than `delayMs`, the following request will be added to queue
|
|
305
|
+
* and either be ignored or exectued based on the debounce/throttle configuration.
|
|
306
|
+
* - If not throttled:
|
|
307
|
+
* 1. Once a request is handled, all previous requests will be ignored and pool starts anew.
|
|
308
|
+
* 2. If a function is provided in the returned callback, ALL of them will be invoked, regardless of pool size.
|
|
309
|
+
* 3. The last/only request in an on-going requests' pool will handled (resolve/reject).
|
|
310
|
+
* - If throttled:
|
|
311
|
+
* 1. Once a requst starts executing, subsequent requests will be added to a queue.
|
|
312
|
+
* 2. The last/only item in the queue will be handled. Rest will be ignored.
|
|
313
|
+
* 3. If a function is provided in the returned callback, it will be invoked only if the request is handled.
|
|
314
|
+
* Thus, improving performance by avoiding unnecessary invokations.
|
|
315
|
+
* 4. If every single request/function needs to be invoked, avoid using throttle.
|
|
316
|
+
* - If throttled and `strict` is truthy, all subsequent request while a request is being handled will be ignored.
|
|
317
|
+
*
|
|
318
|
+
* @param options (optional) Debounce/throttle configuration.
|
|
319
|
+
*
|
|
320
|
+
* The properties' default values can be overridden to be EFFECTIVE GLOBALLY:
|
|
321
|
+
* ```typescript
|
|
322
|
+
* deferred.defaults = {
|
|
323
|
+
* delayMs: 100,
|
|
324
|
+
* resolveError: ResolveError.REJECT,
|
|
325
|
+
* resolveIgnored: ResolveIgnored.WITH_LAST,
|
|
326
|
+
* }
|
|
327
|
+
* ```
|
|
301
328
|
* @property options.delayMs (optional) delay in milliseconds to be used with debounce & throttle modes. When `undefined` or `>= 0`, execution will be sequential.
|
|
302
329
|
* @property options.onError (optional)
|
|
303
330
|
* @property options.onIgnore (optional) invoked whenever callback invocation is ignored by a newer invocation
|
|
@@ -309,30 +336,11 @@ type TimeoutOptions<Func extends string = 'all'> = {
|
|
|
309
336
|
* Requires `defer`.
|
|
310
337
|
* Default: `false`
|
|
311
338
|
*
|
|
312
|
-
* @returns
|
|
313
|
-
* - sequential: when `delayMs <= 0`
|
|
339
|
+
* @returns Callback function that can be invoked in one of the followin 3 methods:
|
|
340
|
+
* - sequential: when `delayMs <= 0`
|
|
314
341
|
* - debounced: when `delayMs > 0` and `throttle = false`
|
|
315
342
|
* - throttled: when `delayMs > 0` and `throttle = true`
|
|
316
343
|
*
|
|
317
|
-
* The main difference is that:
|
|
318
|
-
* - Notes:
|
|
319
|
-
* 1. A "request" simply means invokation of the returned callback function
|
|
320
|
-
* 2. By "handled" it means a "request" will be resolved or rejected.
|
|
321
|
-
* - `PromisE.deferred` is to be used with promises/functions
|
|
322
|
-
* - There is no specific time delay.
|
|
323
|
-
* - The time when a request is completed is irrelevant.
|
|
324
|
-
* - If not throttled:
|
|
325
|
-
* 1. Once a request is handled, all previous requests will be ignored and pool starts anew.
|
|
326
|
-
* 2. If a function is provided in the returned callback, ALL of them will be invoked, regardless of pool size.
|
|
327
|
-
* 3. The last/only request in an on-going requests' pool will handled (resolve/reject).
|
|
328
|
-
* - If throttled:
|
|
329
|
-
* 1. Once a requst starts executing, subsequent requests will be added to a queue.
|
|
330
|
-
* 2. The last/only item in the queue will be handled. Rest will be ignored.
|
|
331
|
-
* 3. If a function is provided in the returned callback, it will be invoked only if the request is handled.
|
|
332
|
-
* Thus, improving performance by avoiding unnecessary invokations.
|
|
333
|
-
* 4. If every single request/function needs to be invoked, avoid using throttle.
|
|
334
|
-
*
|
|
335
|
-
* - If throttled and `strict` is truthy, all subsequent request while a request is being handled will be ignored.
|
|
336
344
|
*
|
|
337
345
|
* @example Explanation & example usage:
|
|
338
346
|
* ```typescript
|
|
@@ -360,7 +368,14 @@ type TimeoutOptions<Func extends string = 'all'> = {
|
|
|
360
368
|
* // `5000` will be printed in the console
|
|
361
369
|
* ```
|
|
362
370
|
*/
|
|
363
|
-
declare function deferred<T>(options?:
|
|
371
|
+
declare function deferred<T, ThisArg = unknown, Delay extends number = number>(options?: DeferredAsyncOptions<ThisArg, Delay>): DeferredAsyncCallback;
|
|
372
|
+
declare namespace deferred {
|
|
373
|
+
var defaults: {
|
|
374
|
+
delayMs: number;
|
|
375
|
+
resolveError: ResolveError.REJECT;
|
|
376
|
+
resolveIgnored: ResolveIgnored.WITH_LAST;
|
|
377
|
+
};
|
|
378
|
+
}
|
|
364
379
|
|
|
365
380
|
/**
|
|
366
381
|
* @function PromisE.deferredCallback
|
|
@@ -394,18 +409,22 @@ declare function deferred<T>(options?: DeferredOptions): DeferredReturn;
|
|
|
394
409
|
* // 200, 600, 1100
|
|
395
410
|
* ```
|
|
396
411
|
*/
|
|
397
|
-
declare function deferredCallback<TDefault, CbArgs extends unknown[] = unknown[]>(callback: (...args: CbArgs) => TDefault | Promise<TDefault>, options?:
|
|
412
|
+
declare function deferredCallback<TDefault, ThisArg, Delay extends number = number, CbArgs extends unknown[] = unknown[]>(callback: (...args: CbArgs) => TDefault | Promise<TDefault>, options?: DeferredAsyncOptions<ThisArg, Delay>): <TResult = TDefault>(...args: CbArgs) => IPromisE<TResult>;
|
|
398
413
|
|
|
399
414
|
/**
|
|
400
|
-
*
|
|
401
|
-
*
|
|
415
|
+
* Creates a promise that completes after given delay/duration.
|
|
416
|
+
*
|
|
417
|
+
* Also accessible from the `PromisE` class as `PromisE.delay()`.
|
|
418
|
+
*
|
|
419
|
+
* @param duration duration in milliseconds. Default: `100`
|
|
420
|
+
* @param result (optional) specify a value to resolve or error to reject with.
|
|
402
421
|
*
|
|
403
|
-
*
|
|
404
|
-
* @param {unknown} result (optional) specify a value to resolve or reject with.
|
|
405
|
-
* Default: `delayMs` when resolved or timed out error when rejected
|
|
406
|
-
* @param {boolean} asRejected (optional) if `true`, will reject the promise after the delay.
|
|
422
|
+
* Alternatively, a function (with no arguments) can be provided that returns the result.
|
|
407
423
|
*
|
|
408
|
-
*
|
|
424
|
+
* Default: `delayMs` when resolved or timed out error when rejected
|
|
425
|
+
* @param asRejected (optional) if `true`, will reject the promise after the delay.
|
|
426
|
+
*
|
|
427
|
+
* @returns a promise
|
|
409
428
|
*
|
|
410
429
|
* @example Delay before continuing execution
|
|
411
430
|
* ```typescript
|
|
@@ -426,6 +445,14 @@ declare function deferredCallback<TDefault, CbArgs extends unknown[] = unknown[]
|
|
|
426
445
|
* ```
|
|
427
446
|
*/
|
|
428
447
|
declare function delay<T = number, TReject extends boolean = boolean>(duration?: number, result?: T | (() => T), asRejected?: TReject): IPromisE_Delay<T>;
|
|
448
|
+
declare namespace delay {
|
|
449
|
+
var defaults: {
|
|
450
|
+
/** Default delay duration in milliseconds */
|
|
451
|
+
duration: number;
|
|
452
|
+
/** Default timed out message (if `result` is not provided) */
|
|
453
|
+
delayTimeoutMsg: string;
|
|
454
|
+
};
|
|
455
|
+
}
|
|
429
456
|
|
|
430
457
|
/**
|
|
431
458
|
* @function PromisE.delayReject
|
|
@@ -462,14 +489,16 @@ declare function delay<T = number, TReject extends boolean = boolean>(duration?:
|
|
|
462
489
|
declare function delayReject<T = never>(duration: number, reason?: unknown): IPromisE_Delay<T>;
|
|
463
490
|
|
|
464
491
|
/**
|
|
465
|
-
*
|
|
466
|
-
*
|
|
492
|
+
* Creates a new promise that wraps one or more promises and rejects if they do not settle within a
|
|
493
|
+
* specified timeout duration. When multiple promises are provided, they can be processed using methods like
|
|
494
|
+
* `all` (default), `race`, `any`, or `allSettled`.
|
|
495
|
+
*
|
|
496
|
+
* @param timeout (optional) timeout duration in milliseconds.
|
|
497
|
+
* Default: `10000` (10 seconds)
|
|
467
498
|
*
|
|
468
|
-
* @param
|
|
469
|
-
* Default: `10000` (10 seconds)
|
|
470
|
-
* @param values promise/function: one or more promises as individual arguments
|
|
499
|
+
* @param values rest param containing one or more promises/values
|
|
471
500
|
*
|
|
472
|
-
* @example
|
|
501
|
+
* @example Wokring with a single promise: resolved succesfully
|
|
473
502
|
* ```typescript
|
|
474
503
|
* PromisE.timeout(
|
|
475
504
|
* 5000, // timeout after 5000ms
|
|
@@ -478,7 +507,16 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
478
507
|
* // Result: 1000
|
|
479
508
|
* ```
|
|
480
509
|
*
|
|
481
|
-
* @example
|
|
510
|
+
* @example Promise times out & rejected
|
|
511
|
+
* ```typescript
|
|
512
|
+
* PromisE.timeout(
|
|
513
|
+
* 5000, // timeout after 5000ms
|
|
514
|
+
* PromisE.delay(20000), // resolves after 20000ms with value 20000
|
|
515
|
+
* ).catch(console.error)
|
|
516
|
+
* // Error: Error('Timed out after 5000ms')
|
|
517
|
+
*```
|
|
518
|
+
*
|
|
519
|
+
* @example Working with multiple promises, resolved using "PromisE.all()"
|
|
482
520
|
*
|
|
483
521
|
* ```typescript
|
|
484
522
|
* PromisE.timeout(
|
|
@@ -490,17 +528,8 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
490
528
|
* // Result: [ 1000, 2000, 3000 ]
|
|
491
529
|
* ```
|
|
492
530
|
*
|
|
493
|
-
* @example
|
|
494
|
-
*
|
|
495
|
-
* PromisE.timeout(
|
|
496
|
-
* 5000, // timeout after 5000ms
|
|
497
|
-
* PromisE.delay(20000), // resolves after 20000ms with value 20000
|
|
498
|
-
* ).catch(console.error)
|
|
499
|
-
* // Error: Error('Timed out after 5000ms')
|
|
500
|
-
*```
|
|
501
|
-
*
|
|
502
|
-
* @example Example 4: timed out & but not rejected.
|
|
503
|
-
* // Eg: when API request is taking longer than expected, print a message but not reject the promise.
|
|
531
|
+
* @example Promise times out & but not rejected.
|
|
532
|
+
* Eg: when API request is taking longer than expected, print a message avoid rejecting the promise.
|
|
504
533
|
* ```typescript
|
|
505
534
|
* const promise = PromisE.timeout(
|
|
506
535
|
* 5000, // timeout after 5000ms
|
|
@@ -512,13 +541,48 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
512
541
|
*
|
|
513
542
|
* // promise timed out >> print/update UI
|
|
514
543
|
* console.log('Request is taking longer than expected......')
|
|
515
|
-
* //
|
|
544
|
+
* // Now return the data promise which is the result of `PromisE.all(promises)` (default).
|
|
516
545
|
* return promise.data
|
|
517
546
|
* })
|
|
518
547
|
*```
|
|
548
|
+
*
|
|
549
|
+
* @example Multiple promises resolved using "PromisE.race()"
|
|
550
|
+
*
|
|
551
|
+
* ```typescript
|
|
552
|
+
* PromisE.timeout(
|
|
553
|
+
* { // instead of `timeout: number` an object can be used for additional options
|
|
554
|
+
* func: 'race', // tells PromisE.timeout to use `PromisE.race(promises)`
|
|
555
|
+
* timeout: 5000, // timeout after 5000ms
|
|
556
|
+
* timeoutMsg: 'My custom timed out message',
|
|
557
|
+
* },
|
|
558
|
+
* PromisE.delay(1000), // resolves after 1000ms with value 1000
|
|
559
|
+
* PromisE.delay(2000), // resolves after 2000ms with value 2000
|
|
560
|
+
* PromisE.delay(3000), // resolves after 3000ms with value 3000
|
|
561
|
+
* ).then(console.log)
|
|
562
|
+
* // Result: 1000 (Result of `Promise.race(promises)`)
|
|
563
|
+
* ```
|
|
564
|
+
*/
|
|
565
|
+
declare function timeout<T extends [unknown, ...unknown[]], // require at least one value
|
|
566
|
+
Result = T['length'] extends 1 ? Awaited<T[0]> : Awaited<T[number]>[]>(timeout: number, ...values: T): IPromisE_Timeout<Result>;
|
|
567
|
+
/**
|
|
568
|
+
*
|
|
569
|
+
* @param options An options object can be passed with one or more of the following properties:
|
|
570
|
+
* @param options.func (optional) Name of the `PromisE` method to be used to combine the `values`.
|
|
571
|
+
* Only used when more than one promise is provided.
|
|
572
|
+
*
|
|
573
|
+
* Accepted values:
|
|
574
|
+
* 1. `'all'` **(default)**: for `PromisE.all`
|
|
575
|
+
* 2. `'allSettled'`: for `PromisE.allSettled`
|
|
576
|
+
* 3. `'any'`: for `PromisE.any`
|
|
577
|
+
* 4. `'race'`: for `PromisE.race`
|
|
578
|
+
*
|
|
579
|
+
* @param options.timeout (optional) timeout duration in milliseconds. Default: `10_000` (10 seconds)
|
|
580
|
+
* @param options.timeoutMsg (optional) custom error message to be used when promises timeout.
|
|
581
|
+
*
|
|
582
|
+
* @param values
|
|
519
583
|
*/
|
|
520
584
|
declare function timeout<T extends [unknown, ...unknown[]], // require at least one value
|
|
521
|
-
TFunc extends keyof TimeoutFunc<T>, Result = T['length'] extends 1 ? Awaited<T[0]> : Awaited<ReturnType<TimeoutFunc<T>[TFunc]>>>(
|
|
585
|
+
TFunc extends keyof TimeoutFunc<T>, Result = T['length'] extends 1 ? Awaited<T[0]> : Awaited<ReturnType<TimeoutFunc<T>[TFunc]>>>(options: TimeoutOptions<TFunc>, ...values: T): IPromisE_Timeout<Result>;
|
|
522
586
|
declare namespace timeout {
|
|
523
587
|
var defaultOptions: Required<TimeoutOptions>;
|
|
524
588
|
}
|
|
@@ -564,29 +628,25 @@ declare namespace timeout {
|
|
|
564
628
|
* ```
|
|
565
629
|
*/
|
|
566
630
|
declare class PromisE<T = unknown> extends PromisEBase<T> {
|
|
567
|
-
|
|
568
|
-
static
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
631
|
+
static deferred: typeof deferred;
|
|
632
|
+
static deferredCallback: typeof deferredCallback;
|
|
633
|
+
static delay: typeof delay;
|
|
634
|
+
static delayReject: typeof delayReject;
|
|
635
|
+
static retry: {
|
|
636
|
+
<T_1>(func: () => _superutils_core.ValueOrPromise<T_1>, options: RetryOptions<T_1>): Promise<T_1>;
|
|
637
|
+
defaults: {
|
|
572
638
|
retry: number;
|
|
573
639
|
retryBackOff: "exponential";
|
|
574
640
|
retryDelay: number;
|
|
575
641
|
retryDelayJitter: true;
|
|
576
642
|
retryDelayJitterMax: number;
|
|
577
|
-
retryIf: null;
|
|
578
643
|
};
|
|
579
644
|
};
|
|
580
|
-
static deferred: typeof deferred;
|
|
581
|
-
static deferredCallback: typeof deferredCallback;
|
|
582
|
-
static delay: typeof delay;
|
|
583
|
-
static delayReject: typeof delayReject;
|
|
584
|
-
static retry: <T_1>(func: () => _superutils_core.ValueOrPromise<T_1>, options?: RetryOptions<T_1>) => Promise<T_1>;
|
|
585
645
|
static timeout: typeof timeout;
|
|
586
646
|
}
|
|
587
647
|
|
|
588
648
|
/**
|
|
589
|
-
* Executes a function and retries it on failure or until a specific condition is met.
|
|
649
|
+
* Executes a function asynchronously and retries it on failure or until a specific condition is met.
|
|
590
650
|
*
|
|
591
651
|
* The function will be re-executed if:
|
|
592
652
|
* 1. The `func` promise rejects or the function throws an error.
|
|
@@ -596,19 +656,63 @@ declare class PromisE<T = unknown> extends PromisEBase<T> {
|
|
|
596
656
|
* Retries will stop when the `retry` count is exhausted, or when `func` executes successfully
|
|
597
657
|
* (resolves without error) AND the `retryIf` (if provided) returns `false`.
|
|
598
658
|
*
|
|
599
|
-
* @template T The type of the value that the `func`
|
|
600
|
-
*
|
|
601
|
-
* @param
|
|
602
|
-
* @
|
|
603
|
-
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
659
|
+
* @template T The type of the value that the `func` resolves to.
|
|
660
|
+
*
|
|
661
|
+
* @param func The function to execute. It can be synchronous or asynchronous.
|
|
662
|
+
* @param options (optional) Configuration of the retry mechanism.
|
|
663
|
+
*
|
|
664
|
+
* The following options' default values can be configured to be EFFECTIVE GLOBALLY.
|
|
665
|
+
*
|
|
666
|
+
* ```typescript
|
|
667
|
+
* PromisE.retry.defaults = {
|
|
668
|
+
* retry: 1,
|
|
669
|
+
* retryBackOff: 'exponential',
|
|
670
|
+
* retryDelay: 300,
|
|
671
|
+
* retryDelayJitter: true,
|
|
672
|
+
* retryDelayJitterMax: 100,
|
|
673
|
+
* }
|
|
674
|
+
* ```
|
|
675
|
+
* @param options.retry (optional) The maximum number of retries. Default: `1`
|
|
676
|
+
* @param options.retryBackOff (optional) The backoff strategy.
|
|
677
|
+
* Accepted values:
|
|
678
|
+
* - `'exponential'` doubles the delay for each subsequent retry.
|
|
679
|
+
* - `'linear'` uses a constant delay.
|
|
680
|
+
*
|
|
681
|
+
* Default: `'exponential'`
|
|
682
|
+
* @param options.retryDelayMs (optional) The base delay in milliseconds between retries.
|
|
683
|
+
*
|
|
684
|
+
* Default: `300`
|
|
685
|
+
* @param options.retryDelayJitter (optional) If true, adds a random jitter to the delay to prevent
|
|
686
|
+
* the thundering herd problem.
|
|
687
|
+
*
|
|
688
|
+
* Default: `true`
|
|
689
|
+
* @param options.retryDelayJitterMax The maximum jitter in milliseconds to add to the delay.
|
|
690
|
+
*
|
|
691
|
+
* Default: `100`
|
|
692
|
+
* @param options.retryIf (optional) A function that is called after a successful execution of `func`.
|
|
693
|
+
* If it returns `true`, a retry is triggered.
|
|
694
|
+
*
|
|
695
|
+
* **Arguments:**
|
|
696
|
+
* - `result`: result received after the most recent `func` excution
|
|
697
|
+
* - `retryCount`: number of times the execution has been retried (`total_attemts - 1`)
|
|
698
|
+
*
|
|
699
|
+
* If `retryIf()` throws error, the are handled gracefully and it's return value defaults `false` (no further retry).
|
|
700
|
+
*
|
|
701
|
+
* @returns A promise that resolves with the result of the last successful execution of `func`.
|
|
702
|
+
* If all retries fail (either by throwing an error or when `retryIf()` returned true in every time),
|
|
703
|
+
* it resolves with the last return value of `func()`. Errors thrown by `func` are caught and handled internally,
|
|
704
|
+
* only re-thrown if no result is received after maximum retries.
|
|
611
705
|
*/
|
|
612
|
-
declare const retry:
|
|
706
|
+
declare const retry: {
|
|
707
|
+
<T>(func: () => ValueOrPromise<T>, options: RetryOptions<T>): Promise<T>;
|
|
708
|
+
/** Global default values */
|
|
709
|
+
defaults: {
|
|
710
|
+
retry: number;
|
|
711
|
+
retryBackOff: "exponential";
|
|
712
|
+
retryDelay: number;
|
|
713
|
+
retryDelayJitter: true;
|
|
714
|
+
retryDelayJitterMax: number;
|
|
715
|
+
};
|
|
716
|
+
};
|
|
613
717
|
|
|
614
|
-
export { type
|
|
718
|
+
export { type DeferredAsyncCallback, type DeferredAsyncDefaults, type DeferredAsyncGetPromise, type DeferredAsyncOptions, type IPromisE, type IPromisE_Delay, type IPromisE_Timeout, type OnEarlyFinalize, PromisE, PromisEBase, type PromiseParams, ResolveError, ResolveIgnored, type RetryOptions, type TimeoutFunc, type TimeoutOptions, PromisE as default, deferred, deferredCallback, delay, delayReject, retry, timeout };
|
package/dist/index.js
CHANGED
|
@@ -1,46 +1,10 @@
|
|
|
1
|
-
// src/types/deferred.ts
|
|
2
|
-
var ResolveError = /* @__PURE__ */ ((ResolveError2) => {
|
|
3
|
-
ResolveError2["NEVER"] = "NEVER";
|
|
4
|
-
ResolveError2["REJECT"] = "REJECT";
|
|
5
|
-
ResolveError2["WITH_ERROR"] = "RESOLVE_ERROR";
|
|
6
|
-
ResolveError2["WITH_UNDEFINED"] = "RESOLVE_UNDEFINED";
|
|
7
|
-
return ResolveError2;
|
|
8
|
-
})(ResolveError || {});
|
|
9
|
-
var ResolveIgnored = /* @__PURE__ */ ((ResolveIgnored2) => {
|
|
10
|
-
ResolveIgnored2["NEVER"] = "NEVER";
|
|
11
|
-
ResolveIgnored2["WITH_LAST"] = "WITH_LAST";
|
|
12
|
-
ResolveIgnored2["WITH_UNDEFINED"] = "WITH_UNDEFINED";
|
|
13
|
-
return ResolveIgnored2;
|
|
14
|
-
})(ResolveIgnored || {});
|
|
15
|
-
|
|
16
|
-
// src/config.ts
|
|
17
|
-
var config = {
|
|
18
|
-
/** Default value for `options` used by `PromisE.*deferred*` functions */
|
|
19
|
-
deferOptions: {
|
|
20
|
-
delayMs: 100,
|
|
21
|
-
resolveError: "REJECT" /* REJECT */,
|
|
22
|
-
resolveIgnored: "WITH_LAST" /* WITH_LAST */,
|
|
23
|
-
throttle: false
|
|
24
|
-
},
|
|
25
|
-
delayTimeoutMsg: "Timed out after",
|
|
26
|
-
retryOptions: {
|
|
27
|
-
retry: 1,
|
|
28
|
-
retryBackOff: "exponential",
|
|
29
|
-
retryDelay: 300,
|
|
30
|
-
retryDelayJitter: true,
|
|
31
|
-
retryDelayJitterMax: 100,
|
|
32
|
-
retryIf: null
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
var config_default = config;
|
|
36
|
-
|
|
37
1
|
// src/deferred.ts
|
|
38
2
|
import {
|
|
39
3
|
deferred as deferredCore,
|
|
40
4
|
fallbackIfFails as fallbackIfFails2,
|
|
41
|
-
forceCast,
|
|
42
5
|
isFn as isFn2,
|
|
43
6
|
isPositiveNumber,
|
|
7
|
+
objCopy,
|
|
44
8
|
throttled as throttledCore
|
|
45
9
|
} from "@superutils/core";
|
|
46
10
|
|
|
@@ -185,17 +149,33 @@ _PromisEBase.withResolvers = () => {
|
|
|
185
149
|
var PromisEBase = _PromisEBase;
|
|
186
150
|
var PromisEBase_default = PromisEBase;
|
|
187
151
|
|
|
152
|
+
// src/types/deferred.ts
|
|
153
|
+
var ResolveError = /* @__PURE__ */ ((ResolveError2) => {
|
|
154
|
+
ResolveError2["NEVER"] = "NEVER";
|
|
155
|
+
ResolveError2["REJECT"] = "REJECT";
|
|
156
|
+
ResolveError2["WITH_ERROR"] = "RESOLVE_ERROR";
|
|
157
|
+
ResolveError2["WITH_UNDEFINED"] = "RESOLVE_UNDEFINED";
|
|
158
|
+
return ResolveError2;
|
|
159
|
+
})(ResolveError || {});
|
|
160
|
+
var ResolveIgnored = /* @__PURE__ */ ((ResolveIgnored2) => {
|
|
161
|
+
ResolveIgnored2["NEVER"] = "NEVER";
|
|
162
|
+
ResolveIgnored2["WITH_LAST"] = "WITH_LAST";
|
|
163
|
+
ResolveIgnored2["WITH_UNDEFINED"] = "WITH_UNDEFINED";
|
|
164
|
+
return ResolveIgnored2;
|
|
165
|
+
})(ResolveIgnored || {});
|
|
166
|
+
|
|
188
167
|
// src/deferred.ts
|
|
189
|
-
function deferred(options
|
|
190
|
-
const defaults =
|
|
168
|
+
function deferred(options) {
|
|
169
|
+
const { defaults } = deferred;
|
|
170
|
+
options = objCopy(defaults, options, [], "empty");
|
|
191
171
|
let { onError, onIgnore, onResult } = options;
|
|
192
172
|
const {
|
|
193
|
-
delayMs
|
|
194
|
-
resolveError
|
|
173
|
+
delayMs,
|
|
174
|
+
resolveError,
|
|
195
175
|
// by default reject on error
|
|
196
|
-
resolveIgnored
|
|
176
|
+
resolveIgnored,
|
|
197
177
|
thisArg,
|
|
198
|
-
throttle
|
|
178
|
+
throttle
|
|
199
179
|
} = options;
|
|
200
180
|
let lastPromisE = null;
|
|
201
181
|
const queue = /* @__PURE__ */ new Map();
|
|
@@ -273,10 +253,15 @@ function deferred(options = {}) {
|
|
|
273
253
|
qItem.started = false;
|
|
274
254
|
queue.set(id, qItem);
|
|
275
255
|
if (gotDelay || !lastPromisE) execute(id, qItem);
|
|
276
|
-
return
|
|
256
|
+
return qItem;
|
|
277
257
|
};
|
|
278
258
|
return deferredFunc;
|
|
279
259
|
}
|
|
260
|
+
deferred.defaults = {
|
|
261
|
+
delayMs: 100,
|
|
262
|
+
resolveError: "REJECT" /* REJECT */,
|
|
263
|
+
resolveIgnored: "WITH_LAST" /* WITH_LAST */
|
|
264
|
+
};
|
|
280
265
|
var deferred_default = deferred;
|
|
281
266
|
|
|
282
267
|
// src/deferredCallback.ts
|
|
@@ -290,7 +275,7 @@ var deferredCallback_default = deferredCallback;
|
|
|
290
275
|
|
|
291
276
|
// src/delay.ts
|
|
292
277
|
import { fallbackIfFails as fallbackIfFails3, isFn as isFn3 } from "@superutils/core";
|
|
293
|
-
function delay(duration =
|
|
278
|
+
function delay(duration = delay.defaults.duration, result = duration, asRejected = false) {
|
|
294
279
|
const promise = new PromisEBase_default();
|
|
295
280
|
const finalize = (result2) => {
|
|
296
281
|
var _a;
|
|
@@ -298,7 +283,9 @@ function delay(duration = 100, result = duration, asRejected = false) {
|
|
|
298
283
|
result2 = (_a = fallbackIfFails3(result2, [], void 0)) != null ? _a : duration;
|
|
299
284
|
if (!asRejected) return promise.resolve(result2);
|
|
300
285
|
promise.reject(
|
|
301
|
-
result2
|
|
286
|
+
duration !== result2 && result2 !== void 0 ? result2 : new Error(
|
|
287
|
+
`${delay.defaults.delayTimeoutMsg} ${duration}ms`
|
|
288
|
+
)
|
|
302
289
|
);
|
|
303
290
|
};
|
|
304
291
|
promise.timeoutId = setTimeout(() => finalize(result), duration);
|
|
@@ -307,6 +294,12 @@ function delay(duration = 100, result = duration, asRejected = false) {
|
|
|
307
294
|
}).finally(() => promise.pause());
|
|
308
295
|
return promise;
|
|
309
296
|
}
|
|
297
|
+
delay.defaults = {
|
|
298
|
+
/** Default delay duration in milliseconds */
|
|
299
|
+
duration: 100,
|
|
300
|
+
/** Default timed out message (if `result` is not provided) */
|
|
301
|
+
delayTimeoutMsg: "Timed out after"
|
|
302
|
+
};
|
|
310
303
|
var delay_default = delay;
|
|
311
304
|
|
|
312
305
|
// src/delayReject.ts
|
|
@@ -316,42 +309,65 @@ function delayReject(duration, reason) {
|
|
|
316
309
|
var delayReject_default = delayReject;
|
|
317
310
|
|
|
318
311
|
// src/retry.ts
|
|
319
|
-
import {
|
|
320
|
-
|
|
321
|
-
|
|
312
|
+
import {
|
|
313
|
+
fallbackIfFails as fallbackIfFails4,
|
|
314
|
+
isEmpty,
|
|
315
|
+
isPositiveInteger,
|
|
316
|
+
objCopy as objCopy2
|
|
317
|
+
} from "@superutils/core";
|
|
318
|
+
var retry = async (func, options) => {
|
|
319
|
+
options = objCopy2(retry.defaults, options != null ? options : {}, [], (key, value) => {
|
|
320
|
+
switch (key) {
|
|
321
|
+
// case 'retryDelayJitter':
|
|
322
|
+
// return true
|
|
323
|
+
case "retry":
|
|
324
|
+
// eslint-disable-next-line no-fallthrough
|
|
325
|
+
case "retryDelay":
|
|
326
|
+
case "retryDelayJitterMax":
|
|
327
|
+
return value !== 0 && !isPositiveInteger(value);
|
|
328
|
+
}
|
|
329
|
+
return !!isEmpty(value);
|
|
330
|
+
});
|
|
322
331
|
const {
|
|
323
|
-
|
|
324
|
-
retryBackOff
|
|
325
|
-
|
|
332
|
+
retry: maxRetries,
|
|
333
|
+
retryBackOff,
|
|
334
|
+
retryDelay,
|
|
335
|
+
retryDelayJitter,
|
|
336
|
+
retryDelayJitterMax
|
|
326
337
|
} = options;
|
|
327
|
-
let
|
|
328
|
-
retry: maxRetries = d.retry,
|
|
329
|
-
retryDelay: delayMs,
|
|
330
|
-
retryDelayJitterMax: jitterMax
|
|
331
|
-
} = options;
|
|
332
|
-
if (maxRetries !== 0 && !isPositiveInteger(maxRetries)) maxRetries = d.retry;
|
|
333
|
-
if (!isPositiveInteger(delayMs)) delayMs = d.retryDelay;
|
|
334
|
-
if (!isPositiveInteger(jitterMax)) jitterMax = d.retryDelayJitterMax;
|
|
338
|
+
let _retryDelay = retryDelay;
|
|
335
339
|
let retryCount = -1;
|
|
336
340
|
let result;
|
|
337
341
|
let error;
|
|
338
342
|
let shouldRetry = false;
|
|
339
343
|
do {
|
|
340
344
|
retryCount++;
|
|
341
|
-
if (retryBackOff === "exponential" && retryCount > 1)
|
|
342
|
-
if (retryDelayJitter)
|
|
343
|
-
|
|
345
|
+
if (retryBackOff === "exponential" && retryCount > 1) _retryDelay *= 2;
|
|
346
|
+
if (retryDelayJitter)
|
|
347
|
+
_retryDelay += Math.floor(Math.random() * retryDelayJitterMax);
|
|
348
|
+
retryCount > 0 && await delay_default(_retryDelay);
|
|
344
349
|
try {
|
|
345
350
|
error = void 0;
|
|
346
351
|
result = await func();
|
|
347
352
|
} catch (err) {
|
|
348
353
|
error = err;
|
|
349
354
|
}
|
|
350
|
-
shouldRetry = maxRetries > 0 && retryCount < maxRetries && (!!error || !!
|
|
355
|
+
shouldRetry = maxRetries > 0 && retryCount < maxRetries && (!!error || !!await fallbackIfFails4(
|
|
356
|
+
options.retryIf,
|
|
357
|
+
[result, retryCount],
|
|
358
|
+
false
|
|
359
|
+
));
|
|
351
360
|
} while (shouldRetry);
|
|
352
361
|
if (error !== void 0) return Promise.reject(error);
|
|
353
362
|
return result;
|
|
354
363
|
};
|
|
364
|
+
retry.defaults = {
|
|
365
|
+
retry: 1,
|
|
366
|
+
retryBackOff: "exponential",
|
|
367
|
+
retryDelay: 300,
|
|
368
|
+
retryDelayJitter: true,
|
|
369
|
+
retryDelayJitterMax: 100
|
|
370
|
+
};
|
|
355
371
|
var retry_default = retry;
|
|
356
372
|
|
|
357
373
|
// src/timeout.ts
|
|
@@ -397,8 +413,6 @@ var timeout_default = timeout;
|
|
|
397
413
|
// src/PromisE.ts
|
|
398
414
|
var PromisE = class extends PromisEBase_default {
|
|
399
415
|
};
|
|
400
|
-
/** Global configuration & default values */
|
|
401
|
-
PromisE.config = config_default;
|
|
402
416
|
PromisE.deferred = deferred_default;
|
|
403
417
|
PromisE.deferredCallback = deferredCallback_default;
|
|
404
418
|
PromisE.delay = delay_default;
|
|
@@ -414,7 +428,6 @@ export {
|
|
|
414
428
|
PromisEBase,
|
|
415
429
|
ResolveError,
|
|
416
430
|
ResolveIgnored,
|
|
417
|
-
config,
|
|
418
431
|
index_default as default,
|
|
419
432
|
deferred,
|
|
420
433
|
deferredCallback,
|
package/package.json
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
"url": "https://github.com/alien45/superutils/issues"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@superutils/core": "1.0.
|
|
7
|
+
"@superutils/core": "^1.0.5"
|
|
8
8
|
},
|
|
9
|
-
"description": "An extended Promise
|
|
9
|
+
"description": "An extended Promise with extra features such as status tracking, deferred/throttled execution, timeout and retry mechanism.",
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"README.md",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"main": "dist/index.js",
|
|
24
24
|
"name": "@superutils/promise",
|
|
25
25
|
"peerDpendencies": {
|
|
26
|
-
"@superutils/core": "1.0.
|
|
26
|
+
"@superutils/core": "^1.0.5"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
@@ -37,10 +37,11 @@
|
|
|
37
37
|
"_watch": "tsc -p tsconfig.json --watch",
|
|
38
38
|
"build": "tsup src/index.ts --format esm --dts --clean --config ../../tsup.config.js",
|
|
39
39
|
"dev": "npm run build -- --watch",
|
|
40
|
+
"start": "npm run build -- --watch",
|
|
40
41
|
"test": "cd ../../ && npm run test promise"
|
|
41
42
|
},
|
|
42
43
|
"sideEffects": false,
|
|
43
44
|
"type": "module",
|
|
44
45
|
"types": "dist/index.d.ts",
|
|
45
|
-
"version": "1.0.
|
|
46
|
+
"version": "1.0.6"
|
|
46
47
|
}
|