@superutils/promise 1.0.5 → 1.0.7
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 +1 -1
- package/dist/index.d.ts +100 -46
- package/dist/index.js +17 -12
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
An extended `Promise` implementation, named `PromisE`, that provides additional features and utilities for easier asynchronous flow control in JavaScript and TypeScript applications.
|
|
4
4
|
|
|
5
|
-
This package offers a drop-in replacement for the native `Promise` that includes status tracking (`.pending`, `.resolved`, `.rejected`) and a suite of
|
|
5
|
+
This package offers a drop-in replacement for the native `Promise` that includes status tracking (`.pending`, `.resolved`, `.rejected`) and a suite of practical static methods for common asynchronous patterns like deferred execution, throttling, and cancellable fetches.
|
|
6
6
|
|
|
7
7
|
<div v-if="false">
|
|
8
8
|
|
package/dist/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ interface IPromisE<T = unknown> extends Promise<T> {
|
|
|
17
17
|
/** Indicates if the promise has been resolved */
|
|
18
18
|
readonly resolved: boolean;
|
|
19
19
|
}
|
|
20
|
-
interface IPromisE_Delay<T = unknown> extends IPromisE<T> {
|
|
20
|
+
interface IPromisE_Delay<T = unknown> extends Promise<T>, IPromisE<T> {
|
|
21
21
|
/**
|
|
22
22
|
* Caution: pausing will prevent the promise from resolving/rejeting automatically.
|
|
23
23
|
*
|
|
@@ -58,6 +58,7 @@ interface IPromisE_Delay<T = unknown> extends IPromisE<T> {
|
|
|
58
58
|
* ```
|
|
59
59
|
*/
|
|
60
60
|
pause: () => void;
|
|
61
|
+
/** Timeout ID */
|
|
61
62
|
timeoutId: TimeoutId;
|
|
62
63
|
}
|
|
63
64
|
/**
|
|
@@ -184,13 +185,13 @@ type RetryOptions<T = unknown> = {
|
|
|
184
185
|
* Additional condition/function to be used to determine whether function should be retried.
|
|
185
186
|
* `retryIf` will only be executed when function execution is successful.
|
|
186
187
|
*/
|
|
187
|
-
retryIf?: null | ((prevResult: T | undefined, retryCount: number
|
|
188
|
+
retryIf?: null | ((prevResult: T | undefined, retryCount: number) => boolean | Promise<boolean>);
|
|
188
189
|
};
|
|
189
190
|
|
|
190
191
|
declare class PromisEBase<T = unknown> extends Promise<T> implements IPromisE<T> {
|
|
191
|
-
readonly state: 0 | 1 | 2;
|
|
192
192
|
private _resolve?;
|
|
193
193
|
private _reject?;
|
|
194
|
+
private _state;
|
|
194
195
|
/**
|
|
195
196
|
* callbacks to be invoked whenever PromisE instance is finalized early using non-static resolve()/reject() methods */
|
|
196
197
|
onEarlyFinalize: OnEarlyFinalize<T>[];
|
|
@@ -219,6 +220,8 @@ declare class PromisEBase<T = unknown> extends Promise<T> implements IPromisE<T>
|
|
|
219
220
|
get rejected(): boolean;
|
|
220
221
|
/** Indicates if the promise has been resolved */
|
|
221
222
|
get resolved(): boolean;
|
|
223
|
+
/** Get promise status code */
|
|
224
|
+
get state(): 0 | 1 | 2;
|
|
222
225
|
/** Resovle pending promise early. */
|
|
223
226
|
resolve: (value: T | PromiseLike<T>) => void;
|
|
224
227
|
/** Reject pending promise early. */
|
|
@@ -293,7 +296,38 @@ type TimeoutOptions<Func extends string = 'all'> = {
|
|
|
293
296
|
* @function PromisE.deferred
|
|
294
297
|
* The adaptation of the `deferred()` function tailored for Promises.
|
|
295
298
|
*
|
|
296
|
-
*
|
|
299
|
+
*
|
|
300
|
+
* # Notes
|
|
301
|
+
*
|
|
302
|
+
* - A "request" simply means invokation of the returned callback function
|
|
303
|
+
* - By "handled" it means a "request" will be resolved or rejected.
|
|
304
|
+
* - `PromisE.deferred` is to be used with promises/functions.
|
|
305
|
+
* `PromisE.deferredCallback` is for use with callback functions.
|
|
306
|
+
* - There is no specific time delay.
|
|
307
|
+
* - If a request takes longer than `delayMs`, the following request will be added to queue
|
|
308
|
+
* and either be ignored or exectued based on the debounce/throttle configuration.
|
|
309
|
+
* - If not throttled:
|
|
310
|
+
* 1. Once a request is handled, all previous requests will be ignored and pool starts anew.
|
|
311
|
+
* 2. If a function is provided in the returned callback, ALL of them will be invoked, regardless of pool size.
|
|
312
|
+
* 3. The last/only request in an on-going requests' pool will handled (resolve/reject).
|
|
313
|
+
* - If throttled:
|
|
314
|
+
* 1. Once a requst starts executing, subsequent requests will be added to a queue.
|
|
315
|
+
* 2. The last/only item in the queue will be handled. Rest will be ignored.
|
|
316
|
+
* 3. If a function is provided in the returned callback, it will be invoked only if the request is handled.
|
|
317
|
+
* Thus, improving performance by avoiding unnecessary invokations.
|
|
318
|
+
* 4. If every single request/function needs to be invoked, avoid using throttle.
|
|
319
|
+
* - If throttled and `strict` is truthy, all subsequent request while a request is being handled will be ignored.
|
|
320
|
+
*
|
|
321
|
+
* @param options (optional) Debounce/throttle configuration.
|
|
322
|
+
*
|
|
323
|
+
* The properties' default values can be overridden to be EFFECTIVE GLOBALLY:
|
|
324
|
+
* ```typescript
|
|
325
|
+
* deferred.defaults = {
|
|
326
|
+
* delayMs: 100,
|
|
327
|
+
* resolveError: ResolveError.REJECT,
|
|
328
|
+
* resolveIgnored: ResolveIgnored.WITH_LAST,
|
|
329
|
+
* }
|
|
330
|
+
* ```
|
|
297
331
|
* @property options.delayMs (optional) delay in milliseconds to be used with debounce & throttle modes. When `undefined` or `>= 0`, execution will be sequential.
|
|
298
332
|
* @property options.onError (optional)
|
|
299
333
|
* @property options.onIgnore (optional) invoked whenever callback invocation is ignored by a newer invocation
|
|
@@ -305,30 +339,11 @@ type TimeoutOptions<Func extends string = 'all'> = {
|
|
|
305
339
|
* Requires `defer`.
|
|
306
340
|
* Default: `false`
|
|
307
341
|
*
|
|
308
|
-
* @returns
|
|
309
|
-
* - sequential: when `delayMs <= 0`
|
|
342
|
+
* @returns Callback function that can be invoked in one of the followin 3 methods:
|
|
343
|
+
* - sequential: when `delayMs <= 0`
|
|
310
344
|
* - debounced: when `delayMs > 0` and `throttle = false`
|
|
311
345
|
* - throttled: when `delayMs > 0` and `throttle = true`
|
|
312
346
|
*
|
|
313
|
-
* The main difference is that:
|
|
314
|
-
* - Notes:
|
|
315
|
-
* 1. A "request" simply means invokation of the returned callback function
|
|
316
|
-
* 2. By "handled" it means a "request" will be resolved or rejected.
|
|
317
|
-
* - `PromisE.deferred` is to be used with promises/functions
|
|
318
|
-
* - There is no specific time delay.
|
|
319
|
-
* - The time when a request is completed is irrelevant.
|
|
320
|
-
* - If not throttled:
|
|
321
|
-
* 1. Once a request is handled, all previous requests will be ignored and pool starts anew.
|
|
322
|
-
* 2. If a function is provided in the returned callback, ALL of them will be invoked, regardless of pool size.
|
|
323
|
-
* 3. The last/only request in an on-going requests' pool will handled (resolve/reject).
|
|
324
|
-
* - If throttled:
|
|
325
|
-
* 1. Once a requst starts executing, subsequent requests will be added to a queue.
|
|
326
|
-
* 2. The last/only item in the queue will be handled. Rest will be ignored.
|
|
327
|
-
* 3. If a function is provided in the returned callback, it will be invoked only if the request is handled.
|
|
328
|
-
* Thus, improving performance by avoiding unnecessary invokations.
|
|
329
|
-
* 4. If every single request/function needs to be invoked, avoid using throttle.
|
|
330
|
-
*
|
|
331
|
-
* - If throttled and `strict` is truthy, all subsequent request while a request is being handled will be ignored.
|
|
332
347
|
*
|
|
333
348
|
* @example Explanation & example usage:
|
|
334
349
|
* ```typescript
|
|
@@ -400,15 +415,19 @@ declare namespace deferred {
|
|
|
400
415
|
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>;
|
|
401
416
|
|
|
402
417
|
/**
|
|
403
|
-
*
|
|
404
|
-
*
|
|
418
|
+
* Creates a promise that completes after given delay/duration.
|
|
419
|
+
*
|
|
420
|
+
* Also accessible from the `PromisE` class as `PromisE.delay()`.
|
|
405
421
|
*
|
|
406
|
-
* @param
|
|
407
|
-
* @param
|
|
408
|
-
* Default: `delayMs` when resolved or timed out error when rejected
|
|
409
|
-
* @param {boolean} asRejected (optional) if `true`, will reject the promise after the delay.
|
|
422
|
+
* @param duration duration in milliseconds. Default: `100`
|
|
423
|
+
* @param result (optional) specify a value to resolve or error to reject with.
|
|
410
424
|
*
|
|
411
|
-
*
|
|
425
|
+
* Alternatively, a function (with no arguments) can be provided that returns the result.
|
|
426
|
+
*
|
|
427
|
+
* Default: `delayMs` when resolved or timed out error when rejected
|
|
428
|
+
* @param asRejected (optional) if `true`, will reject the promise after the delay.
|
|
429
|
+
*
|
|
430
|
+
* @returns a promise
|
|
412
431
|
*
|
|
413
432
|
* @example Delay before continuing execution
|
|
414
433
|
* ```typescript
|
|
@@ -433,7 +452,7 @@ declare namespace delay {
|
|
|
433
452
|
var defaults: {
|
|
434
453
|
/** Default delay duration in milliseconds */
|
|
435
454
|
duration: number;
|
|
436
|
-
/** Default timed out message */
|
|
455
|
+
/** Default timed out message (if `result` is not provided) */
|
|
437
456
|
delayTimeoutMsg: string;
|
|
438
457
|
};
|
|
439
458
|
}
|
|
@@ -630,7 +649,7 @@ declare class PromisE<T = unknown> extends PromisEBase<T> {
|
|
|
630
649
|
}
|
|
631
650
|
|
|
632
651
|
/**
|
|
633
|
-
* Executes a function and retries it on failure or until a specific condition is met.
|
|
652
|
+
* Executes a function asynchronously and retries it on failure or until a specific condition is met.
|
|
634
653
|
*
|
|
635
654
|
* The function will be re-executed if:
|
|
636
655
|
* 1. The `func` promise rejects or the function throws an error.
|
|
@@ -640,21 +659,56 @@ declare class PromisE<T = unknown> extends PromisEBase<T> {
|
|
|
640
659
|
* Retries will stop when the `retry` count is exhausted, or when `func` executes successfully
|
|
641
660
|
* (resolves without error) AND the `retryIf` (if provided) returns `false`.
|
|
642
661
|
*
|
|
643
|
-
* @template T The type of the value that the `func`
|
|
644
|
-
*
|
|
645
|
-
* @param
|
|
646
|
-
* @
|
|
647
|
-
*
|
|
648
|
-
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
662
|
+
* @template T The type of the value that the `func` resolves to.
|
|
663
|
+
*
|
|
664
|
+
* @param func The function to execute. It can be synchronous or asynchronous.
|
|
665
|
+
* @param options (optional) Configuration of the retry mechanism.
|
|
666
|
+
*
|
|
667
|
+
* The following options' default values can be configured to be EFFECTIVE GLOBALLY.
|
|
668
|
+
*
|
|
669
|
+
* ```typescript
|
|
670
|
+
* PromisE.retry.defaults = {
|
|
671
|
+
* retry: 1,
|
|
672
|
+
* retryBackOff: 'exponential',
|
|
673
|
+
* retryDelay: 300,
|
|
674
|
+
* retryDelayJitter: true,
|
|
675
|
+
* retryDelayJitterMax: 100,
|
|
676
|
+
* }
|
|
677
|
+
* ```
|
|
678
|
+
* @param options.retry (optional) The maximum number of retries. Default: `1`
|
|
679
|
+
* @param options.retryBackOff (optional) The backoff strategy.
|
|
680
|
+
* Accepted values:
|
|
681
|
+
* - `'exponential'` doubles the delay for each subsequent retry.
|
|
682
|
+
* - `'linear'` uses a constant delay.
|
|
683
|
+
*
|
|
684
|
+
* Default: `'exponential'`
|
|
685
|
+
* @param options.retryDelayMs (optional) The base delay in milliseconds between retries.
|
|
686
|
+
*
|
|
687
|
+
* Default: `300`
|
|
688
|
+
* @param options.retryDelayJitter (optional) If true, adds a random jitter to the delay to prevent
|
|
689
|
+
* the thundering herd problem.
|
|
690
|
+
*
|
|
691
|
+
* Default: `true`
|
|
692
|
+
* @param options.retryDelayJitterMax The maximum jitter in milliseconds to add to the delay.
|
|
693
|
+
*
|
|
694
|
+
* Default: `100`
|
|
695
|
+
* @param options.retryIf (optional) A function that is called after a successful execution of `func`.
|
|
696
|
+
* If it returns `true`, a retry is triggered.
|
|
697
|
+
*
|
|
698
|
+
* **Arguments:**
|
|
699
|
+
* - `result`: result received after the most recent `func` excution
|
|
700
|
+
* - `retryCount`: number of times the execution has been retried (`total_attemts - 1`)
|
|
701
|
+
*
|
|
702
|
+
* If `retryIf()` throws error, the are handled gracefully and it's return value defaults `false` (no further retry).
|
|
703
|
+
*
|
|
704
|
+
* @returns A promise that resolves with the result of the last successful execution of `func`.
|
|
705
|
+
* If all retries fail (either by throwing an error or when `retryIf()` returned true in every time),
|
|
706
|
+
* it resolves with the last return value of `func()`. Errors thrown by `func` are caught and handled internally,
|
|
707
|
+
* only re-thrown if no result is received after maximum retries.
|
|
655
708
|
*/
|
|
656
709
|
declare const retry: {
|
|
657
710
|
<T>(func: () => ValueOrPromise<T>, options: RetryOptions<T>): Promise<T>;
|
|
711
|
+
/** Global default values */
|
|
658
712
|
defaults: {
|
|
659
713
|
retry: number;
|
|
660
714
|
retryBackOff: "exponential";
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "@superutils/core";
|
|
10
10
|
|
|
11
11
|
// src/PromisEBase.ts
|
|
12
|
-
import {
|
|
12
|
+
import { fallbackIfFails, isFn, isPromise } from "@superutils/core";
|
|
13
13
|
var _PromisEBase = class _PromisEBase extends Promise {
|
|
14
14
|
constructor(input) {
|
|
15
15
|
if (input instanceof _PromisEBase) return input;
|
|
@@ -17,11 +17,11 @@ var _PromisEBase = class _PromisEBase extends Promise {
|
|
|
17
17
|
let _reject;
|
|
18
18
|
super((resolve, reject) => {
|
|
19
19
|
_reject = (reason) => {
|
|
20
|
-
|
|
20
|
+
this._state = 2;
|
|
21
21
|
reject(reason);
|
|
22
22
|
};
|
|
23
23
|
_resolve = (value) => {
|
|
24
|
-
|
|
24
|
+
this._state = 1;
|
|
25
25
|
resolve(value);
|
|
26
26
|
};
|
|
27
27
|
input != null ? input : input = () => {
|
|
@@ -29,7 +29,7 @@ var _PromisEBase = class _PromisEBase extends Promise {
|
|
|
29
29
|
const promise = isPromise(input) ? input : isFn(input) ? new globalThis.Promise(input) : Promise.resolve(input);
|
|
30
30
|
promise.then(_resolve, _reject);
|
|
31
31
|
});
|
|
32
|
-
this.
|
|
32
|
+
this._state = 0;
|
|
33
33
|
/**
|
|
34
34
|
* callbacks to be invoked whenever PromisE instance is finalized early using non-static resolve()/reject() methods */
|
|
35
35
|
this.onEarlyFinalize = [];
|
|
@@ -66,15 +66,19 @@ var _PromisEBase = class _PromisEBase extends Promise {
|
|
|
66
66
|
//
|
|
67
67
|
/** Indicates if the promise is still pending/unfinalized */
|
|
68
68
|
get pending() {
|
|
69
|
-
return this.
|
|
69
|
+
return this._state === 0;
|
|
70
70
|
}
|
|
71
71
|
/** Indicates if the promise has been rejected */
|
|
72
72
|
get rejected() {
|
|
73
|
-
return this.
|
|
73
|
+
return this._state === 2;
|
|
74
74
|
}
|
|
75
75
|
/** Indicates if the promise has been resolved */
|
|
76
76
|
get resolved() {
|
|
77
|
-
return this.
|
|
77
|
+
return this._state === 1;
|
|
78
|
+
}
|
|
79
|
+
/** Get promise status code */
|
|
80
|
+
get state() {
|
|
81
|
+
return this._state;
|
|
78
82
|
}
|
|
79
83
|
// static withResolvers = <T = unknown>() => {
|
|
80
84
|
// const pwr = globalThis.Promise.withResolvers<T>()
|
|
@@ -170,7 +174,6 @@ function deferred(options) {
|
|
|
170
174
|
options = objCopy(defaults, options, [], "empty");
|
|
171
175
|
let { onError, onIgnore, onResult } = options;
|
|
172
176
|
const {
|
|
173
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
174
177
|
delayMs,
|
|
175
178
|
resolveError,
|
|
176
179
|
// by default reject on error
|
|
@@ -259,7 +262,7 @@ function deferred(options) {
|
|
|
259
262
|
return deferredFunc;
|
|
260
263
|
}
|
|
261
264
|
deferred.defaults = {
|
|
262
|
-
delayMs:
|
|
265
|
+
delayMs: 100,
|
|
263
266
|
resolveError: "REJECT" /* REJECT */,
|
|
264
267
|
resolveIgnored: "WITH_LAST" /* WITH_LAST */
|
|
265
268
|
};
|
|
@@ -284,7 +287,9 @@ function delay(duration = delay.defaults.duration, result = duration, asRejected
|
|
|
284
287
|
result2 = (_a = fallbackIfFails3(result2, [], void 0)) != null ? _a : duration;
|
|
285
288
|
if (!asRejected) return promise.resolve(result2);
|
|
286
289
|
promise.reject(
|
|
287
|
-
result2
|
|
290
|
+
duration !== result2 && result2 !== void 0 ? result2 : new Error(
|
|
291
|
+
`${delay.defaults.delayTimeoutMsg} ${duration}ms`
|
|
292
|
+
)
|
|
288
293
|
);
|
|
289
294
|
};
|
|
290
295
|
promise.timeoutId = setTimeout(() => finalize(result), duration);
|
|
@@ -296,7 +301,7 @@ function delay(duration = delay.defaults.duration, result = duration, asRejected
|
|
|
296
301
|
delay.defaults = {
|
|
297
302
|
/** Default delay duration in milliseconds */
|
|
298
303
|
duration: 100,
|
|
299
|
-
/** Default timed out message */
|
|
304
|
+
/** Default timed out message (if `result` is not provided) */
|
|
300
305
|
delayTimeoutMsg: "Timed out after"
|
|
301
306
|
};
|
|
302
307
|
var delay_default = delay;
|
|
@@ -353,7 +358,7 @@ var retry = async (func, options) => {
|
|
|
353
358
|
}
|
|
354
359
|
shouldRetry = maxRetries > 0 && retryCount < maxRetries && (!!error || !!await fallbackIfFails4(
|
|
355
360
|
options.retryIf,
|
|
356
|
-
[result, retryCount
|
|
361
|
+
[result, retryCount],
|
|
357
362
|
false
|
|
358
363
|
));
|
|
359
364
|
} while (shouldRetry);
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"url": "https://github.com/alien45/superutils/issues"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@superutils/core": "^1.0.
|
|
7
|
+
"@superutils/core": "^1.0.7"
|
|
8
8
|
},
|
|
9
9
|
"description": "An extended Promise with extra features such as status tracking, deferred/throttled execution, timeout and retry mechanism.",
|
|
10
10
|
"files": [
|
|
@@ -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.7"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
@@ -43,5 +43,5 @@
|
|
|
43
43
|
"sideEffects": false,
|
|
44
44
|
"type": "module",
|
|
45
45
|
"types": "dist/index.d.ts",
|
|
46
|
-
"version": "1.0.
|
|
46
|
+
"version": "1.0.7"
|
|
47
47
|
}
|