@superutils/promise 1.1.6 → 1.2.1
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 +205 -104
- package/dist/index.js +156 -50
- package/package.json +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as _superutils_core from '@superutils/core';
|
|
2
|
-
import { ValueOrPromise,
|
|
2
|
+
import { ValueOrPromise, PositiveNumber, DeferredOptions, TimeoutId } from '@superutils/core';
|
|
3
3
|
|
|
4
4
|
interface IPromisE<T = unknown> extends Promise<T> {
|
|
5
5
|
/** 0: pending, 1: resolved, 2: rejected */
|
|
6
6
|
readonly state: 0 | 1 | 2;
|
|
7
7
|
/** callbacks to be invoked whenever PromisE instance is finalized early using non-static resolve/reject methods */
|
|
8
8
|
onEarlyFinalize: OnEarlyFinalize<T>[];
|
|
9
|
+
onFinalize: OnFinalize<T>[];
|
|
9
10
|
/** Indicates if the promise is still pending/unfinalized */
|
|
10
11
|
readonly pending: boolean;
|
|
11
12
|
/** Reject pending promise early. */
|
|
@@ -17,64 +18,8 @@ interface IPromisE<T = unknown> extends Promise<T> {
|
|
|
17
18
|
/** Indicates if the promise has been resolved */
|
|
18
19
|
readonly resolved: boolean;
|
|
19
20
|
}
|
|
20
|
-
interface IPromisE_Delay<T = unknown> extends Promise<T>, IPromisE<T> {
|
|
21
|
-
/**
|
|
22
|
-
* Caution: pausing will prevent the promise from resolving/rejeting automatically.
|
|
23
|
-
*
|
|
24
|
-
* In order to finalize the promise either the `resolve()` or the `reject()` method must be invoked manually.
|
|
25
|
-
*
|
|
26
|
-
* An never-finalized promise may cause memory leak and will leave it at the mercry of the garbage collector.
|
|
27
|
-
* Use `pause()` only if you are sure.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* ```typescript
|
|
31
|
-
* // Example 1: SAFE => no memory leak, because no reference to the promise is stored and no suspended code
|
|
32
|
-
* <button onClick={() => {
|
|
33
|
-
* const promise = PromisE.delay(1000).then(... do stuff ....)
|
|
34
|
-
* setTimeout(() => promise.pause(), 300)
|
|
35
|
-
* }}>Click Me</button>
|
|
36
|
-
* ```
|
|
37
|
-
*
|
|
38
|
-
* @example UNSAFE => potential memory leak, because of suspended code
|
|
39
|
-
* ```typescript
|
|
40
|
-
* <button onClick={() => {
|
|
41
|
-
* const promise = PromisE.delay(1000)
|
|
42
|
-
* setTimeout(() => promise.pause(), 300)
|
|
43
|
-
* await promise // suspended code
|
|
44
|
-
* //... do stuff ....
|
|
45
|
-
* }}>Click Me</button>
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @example UNSAFE => potential memory leak, because of preserved reference.
|
|
49
|
-
* ```typescript
|
|
50
|
-
* // Until the reference to promises is collected by the garbage collector,
|
|
51
|
-
* // reference to the unfinished promise will remain in memory.
|
|
52
|
-
* const promises = []
|
|
53
|
-
* <button onClick={() => {
|
|
54
|
-
* const promise = PromisE.delay(1000)
|
|
55
|
-
* setTimeout(() => promise.pause(), 300)
|
|
56
|
-
* promises.push(promise)
|
|
57
|
-
* }}>Click Me</button>
|
|
58
|
-
* ```
|
|
59
|
-
*/
|
|
60
|
-
pause: () => void;
|
|
61
|
-
/** Timeout ID */
|
|
62
|
-
timeoutId: TimeoutId;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Descibes a timeout PromisE and it's additional properties.
|
|
66
|
-
*/
|
|
67
|
-
type IPromisE_Timeout<T = unknown> = IPromisE<T> & {
|
|
68
|
-
/** Clearing the timeout will prevent it from timing out */
|
|
69
|
-
clearTimeout: () => void;
|
|
70
|
-
/** The result/data promise. If more than one supplied in `args` result promise will be a combined `PromisE.all` */
|
|
71
|
-
data: IPromisE<T>;
|
|
72
|
-
/** A shorthand getter to check if the promise has timed out. Same as `promise.timeout.rejected`. */
|
|
73
|
-
readonly timedout: boolean;
|
|
74
|
-
/** The timeout promise */
|
|
75
|
-
timeout: IPromisE_Delay<T>;
|
|
76
|
-
};
|
|
77
21
|
type OnEarlyFinalize<T> = <TResolved extends boolean, TValue = TResolved extends true ? T : unknown>(resolved: TResolved, resultOrReason: TValue) => ValueOrPromise<unknown>;
|
|
22
|
+
type OnFinalize<T> = (result?: T | PromiseLike<T>, error?: unknown) => ValueOrPromise<void>;
|
|
78
23
|
type PromiseParams<T = unknown> = ConstructorParameters<typeof Promise<T>>;
|
|
79
24
|
|
|
80
25
|
/** Return type of `PromisE.deferred()` */
|
|
@@ -96,7 +41,7 @@ type DeferredAsyncOptions<ThisArg = unknown, Delay = unknown> = {
|
|
|
96
41
|
delayMs?: 0 | PositiveNumber<Delay>;
|
|
97
42
|
/**
|
|
98
43
|
* Whether to ignore (based on `resolveIgnored` settings) stale promises.
|
|
99
|
-
* In
|
|
44
|
+
* In debounce/throttle mode, when an older promise is resolved after a newly resolved promise,
|
|
100
45
|
* the older one is considered stale.
|
|
101
46
|
*
|
|
102
47
|
* Default: `false`
|
|
@@ -125,17 +70,13 @@ type DeferredAsyncOptions<ThisArg = unknown, Delay = unknown> = {
|
|
|
125
70
|
* See {@link ResolveError} for available options.
|
|
126
71
|
*/
|
|
127
72
|
resolveError?: ResolveError;
|
|
128
|
-
} & (
|
|
129
|
-
delayMs: 0;
|
|
130
|
-
} & {
|
|
73
|
+
} & (Delay extends 0 ? {
|
|
131
74
|
throttle?: false;
|
|
132
75
|
/** Callback invoked whenever promise/function throws error */
|
|
133
76
|
onError?: (this: ThisArg, err: unknown) => ValueOrPromise<unknown>;
|
|
134
77
|
/** The value to be used as "thisArg" whenever any of the callbacks are invoked */
|
|
135
78
|
thisArg?: ThisArg;
|
|
136
|
-
}
|
|
137
|
-
delayMs?: PositiveNumber<Delay>;
|
|
138
|
-
} & DeferredOptions<ThisArg>));
|
|
79
|
+
} : DeferredOptions<ThisArg>);
|
|
139
80
|
/** Determines what to do when deferred promise/function fails */
|
|
140
81
|
declare enum ResolveError {
|
|
141
82
|
/** Neither resolve nor reject the failed */
|
|
@@ -160,6 +101,51 @@ declare enum ResolveIgnored {
|
|
|
160
101
|
WITH_UNDEFINED = "WITH_UNDEFINED"
|
|
161
102
|
}
|
|
162
103
|
|
|
104
|
+
interface IPromisE_Delay<T = unknown> extends Promise<T>, IPromisE<T> {
|
|
105
|
+
/**
|
|
106
|
+
* Caution: pausing will prevent the promise from resolving/rejeting automatically.
|
|
107
|
+
*
|
|
108
|
+
* In order to finalize the promise either the `resolve()` or the `reject()` method must be invoked manually.
|
|
109
|
+
*
|
|
110
|
+
* An never-finalized promise may cause memory leak and will leave it at the mercry of the garbage collector.
|
|
111
|
+
* Use `pause()` only if you are sure.
|
|
112
|
+
*
|
|
113
|
+
* @example
|
|
114
|
+
* ```typescript
|
|
115
|
+
* // Example 1: SAFE => no memory leak, because no reference to the promise is stored and no suspended code
|
|
116
|
+
* <button onClick={() => {
|
|
117
|
+
* const promise = PromisE.delay(1000).then(... do stuff ....)
|
|
118
|
+
* setTimeout(() => promise.pause(), 300)
|
|
119
|
+
* }}>Click Me</button>
|
|
120
|
+
* ```
|
|
121
|
+
*
|
|
122
|
+
* @example UNSAFE => potential memory leak, because of suspended code
|
|
123
|
+
* ```typescript
|
|
124
|
+
* <button onClick={() => {
|
|
125
|
+
* const promise = PromisE.delay(1000)
|
|
126
|
+
* setTimeout(() => promise.pause(), 300)
|
|
127
|
+
* await promise // suspended code
|
|
128
|
+
* //... do stuff ....
|
|
129
|
+
* }}>Click Me</button>
|
|
130
|
+
* ```
|
|
131
|
+
*
|
|
132
|
+
* @example UNSAFE => potential memory leak, because of preserved reference.
|
|
133
|
+
* ```typescript
|
|
134
|
+
* // Until the reference to promises is collected by the garbage collector,
|
|
135
|
+
* // reference to the unfinished promise will remain in memory.
|
|
136
|
+
* const promises = []
|
|
137
|
+
* <button onClick={() => {
|
|
138
|
+
* const promise = PromisE.delay(1000)
|
|
139
|
+
* setTimeout(() => promise.pause(), 300)
|
|
140
|
+
* promises.push(promise)
|
|
141
|
+
* }}>Click Me</button>
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
pause: () => void;
|
|
145
|
+
/** Timeout ID */
|
|
146
|
+
timeoutId: TimeoutId;
|
|
147
|
+
}
|
|
148
|
+
|
|
163
149
|
/** Function to determine whether retry should be attempted based on previous result/error */
|
|
164
150
|
type RetryIfFunc<T = unknown> = (prevResult: T | undefined, retryCount: number, error?: unknown) => ValueOrPromise<boolean | void>;
|
|
165
151
|
/** Options for automatic retry mechanism */
|
|
@@ -225,6 +211,7 @@ declare class PromisEBase<T = unknown> extends Promise<T> implements IPromisE<T>
|
|
|
225
211
|
/**
|
|
226
212
|
* callbacks to be invoked whenever PromisE instance is finalized early using non-static resolve()/reject() methods */
|
|
227
213
|
onEarlyFinalize: OnEarlyFinalize<T>[];
|
|
214
|
+
onFinalize: OnFinalize<T>[];
|
|
228
215
|
/** Create a PromisE instance as a drop-in replacement for Promise */
|
|
229
216
|
constructor(...args: PromiseParams<T>);
|
|
230
217
|
/** Extend an existing Promise instance to check status or finalize early */
|
|
@@ -273,7 +260,7 @@ declare class PromisEBase<T = unknown> extends Promise<T> implements IPromisE<T>
|
|
|
273
260
|
/** Sugar for `new PromisE(Promise.race(..))` */
|
|
274
261
|
static race: <T_1 extends unknown[]>(values: T_1) => IPromisE<Awaited<T_1[number]>>;
|
|
275
262
|
/** Extends Promise.reject */
|
|
276
|
-
static reject: <T_1 = never>(reason: unknown) =>
|
|
263
|
+
static reject: <T_1 = never>(reason: unknown) => PromisEBase<T_1>;
|
|
277
264
|
/** Sugar for `new PromisE(Promise.resolve(...))` */
|
|
278
265
|
static resolve: <T_1>(value?: T_1 | PromiseLike<T_1>) => IPromisE<T_1>;
|
|
279
266
|
/** Sugar for `new PromisE(Promise.try(...))` */
|
|
@@ -310,25 +297,94 @@ declare class PromisEBase<T = unknown> extends Promise<T> implements IPromisE<T>
|
|
|
310
297
|
};
|
|
311
298
|
}
|
|
312
299
|
|
|
313
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Descibes a timeout PromisE and it's additional properties.
|
|
302
|
+
*/
|
|
303
|
+
type IPromisE_Timeout<T = unknown> = IPromisE<T> & {
|
|
304
|
+
readonly abortCtrl?: AbortController;
|
|
305
|
+
/** Read-only property indicating if the promise rejected because of external abort. */
|
|
306
|
+
readonly aborted: boolean;
|
|
307
|
+
/**
|
|
308
|
+
* Removes `abortCtrl/signal` listeners, effectively disabling external cancellation via AbortController.
|
|
309
|
+
*/
|
|
310
|
+
cancelAbort: () => void;
|
|
311
|
+
/**
|
|
312
|
+
* Clears the timeout timer, preventing the promise from being rejected due to a timeout.
|
|
313
|
+
*/
|
|
314
|
+
clearTimeout: () => void;
|
|
315
|
+
/** The underlying data promise. If multiple promises were passed to `timeout`, this represents the combined result (defaulting to `PromisE.all`). */
|
|
316
|
+
data: IPromisE<T>;
|
|
317
|
+
/** Read-only property indicating if the promise timed out. Equivalent to checking `promise.timeout.rejected`. */
|
|
318
|
+
readonly timedout: boolean;
|
|
319
|
+
/** The internal promise that handles the timeout logic. It rejects when the duration expires. */
|
|
320
|
+
timeout: IPromisE_Delay<T>;
|
|
321
|
+
};
|
|
322
|
+
type TimeoutResult<T extends unknown[], BatchFunc extends keyof BatchFuncs<T>, Values extends unknown[] = {
|
|
323
|
+
-readonly [P in keyof T]: T[P] extends (...args: unknown[]) => infer ReturnType ? ReturnType : T[P];
|
|
324
|
+
}> = Awaited<T['length'] extends 1 ? Values[0] : ReturnType<BatchFuncs<Values>[BatchFunc]>>;
|
|
325
|
+
/** Suported function names for batch operations */
|
|
326
|
+
type BatchFuncs<T extends unknown[] = []> = {
|
|
314
327
|
all: typeof PromisEBase.all<T>;
|
|
315
328
|
allSettled: typeof PromisEBase.allSettled<T>;
|
|
316
329
|
any: typeof PromisEBase.any<T>;
|
|
317
330
|
race: typeof PromisEBase.race<T>;
|
|
318
331
|
};
|
|
319
332
|
/**
|
|
320
|
-
* `PromisE.timeout`
|
|
333
|
+
* Options for `PromisE.timeout()`
|
|
321
334
|
*
|
|
322
|
-
* @param func (optional) name of the supported `
|
|
335
|
+
* @param func (optional) name of the supported `PromiEBase` static method to be used to resolve
|
|
336
|
+
* when more than one promise/function is provided. Default: `"all"`
|
|
323
337
|
* @param timeout (optional) timeout duration in milliseconds. Default: `10_000` (10 seconds)
|
|
324
|
-
* @param timeoutMsg (optional) timeout error message. Default: `"Timed out after 10000ms"`
|
|
325
338
|
*
|
|
326
339
|
*/
|
|
327
|
-
type TimeoutOptions<
|
|
328
|
-
|
|
340
|
+
type TimeoutOptions<T extends unknown[] = [], BatchFuncName extends string = 'all'> = {
|
|
341
|
+
/**
|
|
342
|
+
* An `AbortController` instance.
|
|
343
|
+
*
|
|
344
|
+
* If provided:
|
|
345
|
+
* - It will be aborted automatically when the timeout occurs.
|
|
346
|
+
* - If it is aborted externally, the promise will be rejected and the timeout will be cleared.
|
|
347
|
+
*/
|
|
348
|
+
abortCtrl?: AbortController;
|
|
349
|
+
/**
|
|
350
|
+
* Whether to call `abortCtrl.abort()` if the promise is finalized externally
|
|
351
|
+
* (resolved or rejected before timeout or abort).
|
|
352
|
+
*
|
|
353
|
+
* Default: `true`
|
|
354
|
+
*/
|
|
355
|
+
abortOnEarlyFinalize?: boolean;
|
|
356
|
+
/**
|
|
357
|
+
* The name of the `PromisEBase` static method to use for resolving multiple promises/functions.
|
|
358
|
+
*
|
|
359
|
+
* Only applicable when more than one promise/function is provided.
|
|
360
|
+
*/
|
|
361
|
+
batchFunc?: T['length'] extends 0 ? never : T['length'] extends 1 ? never : BatchFuncName;
|
|
362
|
+
/**
|
|
363
|
+
* Callback invoked when the promise is rejected due to an abort signal.
|
|
364
|
+
*
|
|
365
|
+
* Can be used to transform the abort error by returning a custom `Error` object.
|
|
366
|
+
*/
|
|
367
|
+
onAbort?: () => ValueOrPromise<void | Error>;
|
|
368
|
+
/**
|
|
369
|
+
* Callback invoked when the promise times out.
|
|
370
|
+
*
|
|
371
|
+
* Can be used to transform the timeout error by returning a custom `Error` object.
|
|
372
|
+
*/
|
|
373
|
+
onTimeout?: () => ValueOrPromise<void | Error>;
|
|
374
|
+
/**
|
|
375
|
+
* An `AbortSignal` to listen to.
|
|
376
|
+
*
|
|
377
|
+
* If aborted:
|
|
378
|
+
* - The promise will be rejected.
|
|
379
|
+
* - The `abortCtrl` (if provided and distinct) will be aborted.
|
|
380
|
+
* - The timeout will be cleared.
|
|
381
|
+
*/
|
|
382
|
+
signal?: AbortSignal;
|
|
383
|
+
/** Timeout duration in milliseconds. */
|
|
329
384
|
timeout?: number;
|
|
330
|
-
timeoutMsg?: string;
|
|
331
385
|
};
|
|
386
|
+
/** Default options for `PromisE.timeout()` */
|
|
387
|
+
type TimeoutOptionsDefault = Required<Omit<TimeoutOptions<unknown[], keyof BatchFuncs>, 'abortCtrl' | 'signal'>>;
|
|
332
388
|
|
|
333
389
|
/**
|
|
334
390
|
* @function PromisE.deferred
|
|
@@ -521,7 +577,7 @@ declare function deferredCallback<TDefault = unknown, ThisArg = unknown, Delay =
|
|
|
521
577
|
* func()
|
|
522
578
|
* ```
|
|
523
579
|
*/
|
|
524
|
-
declare function delay<T = number, TReject extends boolean = boolean>(duration?: number, result?: T | (() => T), asRejected?: TReject): IPromisE_Delay<T>;
|
|
580
|
+
declare function delay<T = number, TReject extends boolean = boolean>(duration?: number, result?: T | (() => T | Promise<T>), asRejected?: TReject): IPromisE_Delay<T>;
|
|
525
581
|
declare namespace delay {
|
|
526
582
|
var defaults: {
|
|
527
583
|
/** Default delay duration in milliseconds */
|
|
@@ -571,12 +627,14 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
571
627
|
* `all` (default), `race`, `any`, or `allSettled`.
|
|
572
628
|
*
|
|
573
629
|
* @param timeout (optional) timeout duration in milliseconds.
|
|
574
|
-
* Default: `
|
|
630
|
+
* Default: `10_000` (10 seconds)
|
|
575
631
|
*
|
|
576
632
|
* @param values rest param containing one or more promises/values
|
|
577
633
|
*
|
|
578
|
-
* @example
|
|
634
|
+
* @example Working with a single promise
|
|
579
635
|
* ```typescript
|
|
636
|
+
* import PromisE from '@supertuils/promise'
|
|
637
|
+
*
|
|
580
638
|
* PromisE.timeout(
|
|
581
639
|
* 5000, // timeout after 5000ms
|
|
582
640
|
* PromisE.delay(1000), // resolves after 1000ms with value 1000
|
|
@@ -584,8 +642,21 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
584
642
|
* // Result: 1000
|
|
585
643
|
* ```
|
|
586
644
|
*
|
|
645
|
+
* @example Working with a single function
|
|
646
|
+
* ```typescript
|
|
647
|
+
* import PromisE from '@supertuils/promise'
|
|
648
|
+
*
|
|
649
|
+
* PromisE.timeout(
|
|
650
|
+
* 5000, // timeout after 5000ms
|
|
651
|
+
* () => PromisE.delay(1000), // function resolves after 1000ms with value 1000
|
|
652
|
+
* ).then(console.log)
|
|
653
|
+
* // Result: 1000
|
|
654
|
+
* ```
|
|
655
|
+
*
|
|
587
656
|
* @example Promise times out & rejected
|
|
588
657
|
* ```typescript
|
|
658
|
+
* import PromisE from '@supertuils/promise'
|
|
659
|
+
*
|
|
589
660
|
* PromisE.timeout(
|
|
590
661
|
* 5000, // timeout after 5000ms
|
|
591
662
|
* PromisE.delay(20000), // resolves after 20000ms with value 20000
|
|
@@ -593,13 +664,15 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
593
664
|
* // Error: Error('Timed out after 5000ms')
|
|
594
665
|
*```
|
|
595
666
|
*
|
|
596
|
-
* @example Working with multiple promises, resolved using "PromisE.all()"
|
|
667
|
+
* @example Working with multiple promises/functions, resolved using "PromisE.all()"
|
|
597
668
|
*
|
|
598
669
|
* ```typescript
|
|
670
|
+
* import PromisE from '@supertuils/promise'
|
|
671
|
+
*
|
|
599
672
|
* PromisE.timeout(
|
|
600
673
|
* 5000, // timeout after 5000ms
|
|
601
674
|
* PromisE.delay(1000), // resolves after 1000ms with value 1000
|
|
602
|
-
* PromisE.delay(2000), // resolves after 2000ms with value 2000
|
|
675
|
+
* () => PromisE.delay(2000), // resolves after 2000ms with value 2000
|
|
603
676
|
* PromisE.delay(3000), // resolves after 3000ms with value 3000
|
|
604
677
|
* ).then(console.log)
|
|
605
678
|
* // Result: [ 1000, 2000, 3000 ]
|
|
@@ -608,6 +681,8 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
608
681
|
* @example Promise times out & but not rejected.
|
|
609
682
|
* Eg: when API request is taking longer than expected, print a message avoid rejecting the promise.
|
|
610
683
|
* ```typescript
|
|
684
|
+
* import PromisE from '@supertuils/promise'
|
|
685
|
+
*
|
|
611
686
|
* const promise = PromisE.timeout(
|
|
612
687
|
* 5000, // timeout after 5000ms
|
|
613
688
|
* PromisE.delay(20000), // data promise, resolves after 20000ms with value 20000
|
|
@@ -622,46 +697,49 @@ declare function delayReject<T = never>(duration: number, reason?: unknown): IPr
|
|
|
622
697
|
* return promise.data
|
|
623
698
|
* })
|
|
624
699
|
*```
|
|
700
|
+
*/
|
|
701
|
+
declare function timeout<T extends [unknown, ...unknown[]]>(timeout: number, ...values: T): IPromisE_Timeout<TimeoutResult<T, 'all'>>;
|
|
702
|
+
/**
|
|
703
|
+
*
|
|
704
|
+
* @param options An options object can be passed with one or more of the following properties:
|
|
705
|
+
* @param options.abortCtrl (optional) AbortController to manually reject promise externally and/or to sync abort with timeout rejection
|
|
706
|
+
* @param options.func (optional) Name of the `PromisE` static method to be used to combine the `values`.
|
|
707
|
+
* Only used when more than one promise is provided. Default: `"all"`
|
|
708
|
+
*
|
|
709
|
+
* Accepted values:
|
|
710
|
+
* 1. `'all'` **(default)**: for `PromisE.all`
|
|
711
|
+
* 2. `'allSettled'`: for `PromisE.allSettled`
|
|
712
|
+
* 3. `'any'`: for `PromisE.any`
|
|
713
|
+
* 4. `'race'`: for `PromisE.race`
|
|
714
|
+
* @param options.onAbort (optional) Callback invoked when the promise is rejected due to an abort signal.
|
|
715
|
+
* Optionally, return an `Error` object to reject the promise with a custom error.
|
|
716
|
+
* @param options.onTimeout (optional) Callback invoked when the promise times out.
|
|
717
|
+
* Optionally, return an `Error` object to reject the promise with a custom error.
|
|
718
|
+
* @param options.signal (optional) AbortSignal to manually reject promise externally
|
|
719
|
+
* @param options.timeout (optional) timeout duration in milliseconds. If positive number is not provided, the default value will be used. Default: `10_000` (10 seconds)
|
|
720
|
+
*
|
|
721
|
+
* @param values Mix of promises, values and/or functions
|
|
625
722
|
*
|
|
626
|
-
* @example
|
|
723
|
+
* @example Working with multiple promises/functions resolved using "PromisE.race()"
|
|
627
724
|
*
|
|
628
725
|
* ```typescript
|
|
726
|
+
* import PromisE from '@supertuils/promise'
|
|
727
|
+
*
|
|
629
728
|
* PromisE.timeout(
|
|
630
729
|
* { // instead of `timeout: number` an object can be used for additional options
|
|
631
730
|
* func: 'race', // tells PromisE.timeout to use `PromisE.race(promises)`
|
|
632
731
|
* timeout: 5000, // timeout after 5000ms
|
|
633
|
-
* timeoutMsg: 'My custom timed out message',
|
|
634
732
|
* },
|
|
635
733
|
* PromisE.delay(1000), // resolves after 1000ms with value 1000
|
|
636
|
-
* PromisE.delay(2000), // resolves after 2000ms with value 2000
|
|
734
|
+
* () => PromisE.delay(2000), // resolves after 2000ms with value 2000
|
|
637
735
|
* PromisE.delay(3000), // resolves after 3000ms with value 3000
|
|
638
736
|
* ).then(console.log)
|
|
639
737
|
* // Result: 1000 (Result of `Promise.race(promises)`)
|
|
640
738
|
* ```
|
|
641
739
|
*/
|
|
642
|
-
declare function timeout<T extends
|
|
643
|
-
Result = T['length'] extends 1 ? Awaited<T[0]> : Awaited<T[number]>[]>(timeout: number, ...values: T): IPromisE_Timeout<Result>;
|
|
644
|
-
/**
|
|
645
|
-
*
|
|
646
|
-
* @param options An options object can be passed with one or more of the following properties:
|
|
647
|
-
* @param options.func (optional) Name of the `PromisE` method to be used to combine the `values`.
|
|
648
|
-
* Only used when more than one promise is provided.
|
|
649
|
-
*
|
|
650
|
-
* Accepted values:
|
|
651
|
-
* 1. `'all'` **(default)**: for `PromisE.all`
|
|
652
|
-
* 2. `'allSettled'`: for `PromisE.allSettled`
|
|
653
|
-
* 3. `'any'`: for `PromisE.any`
|
|
654
|
-
* 4. `'race'`: for `PromisE.race`
|
|
655
|
-
*
|
|
656
|
-
* @param options.timeout (optional) timeout duration in milliseconds. Default: `10_000` (10 seconds)
|
|
657
|
-
* @param options.timeoutMsg (optional) custom error message to be used when promises timeout.
|
|
658
|
-
*
|
|
659
|
-
* @param values
|
|
660
|
-
*/
|
|
661
|
-
declare function timeout<T extends [unknown, ...unknown[]], // require at least one value
|
|
662
|
-
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>;
|
|
740
|
+
declare function timeout<T extends unknown[], TFunc extends keyof BatchFuncs<T> = keyof BatchFuncs<T>>(options: TimeoutOptions<T, TFunc>, ...values: T): IPromisE_Timeout<TimeoutResult<T, TFunc>>;
|
|
663
741
|
declare namespace timeout {
|
|
664
|
-
var
|
|
742
|
+
var defaults: Required<Omit<TimeoutOptions<unknown[], keyof BatchFuncs<[]>>, "abortCtrl" | "signal">>;
|
|
665
743
|
}
|
|
666
744
|
|
|
667
745
|
/**
|
|
@@ -792,4 +870,27 @@ declare const retry: {
|
|
|
792
870
|
};
|
|
793
871
|
};
|
|
794
872
|
|
|
795
|
-
|
|
873
|
+
/** Timeout duration (in milliseconds) used as a fallback when positive number is not provided to {@link timeout} */
|
|
874
|
+
declare const TIMEOUT_FALLBACK = 10000;
|
|
875
|
+
/** Node.js setTimeout limit is 2147483647 (2^31-1). Larger values fire immediately. */
|
|
876
|
+
declare const TIMEOUT_MAX = 2147483647;
|
|
877
|
+
declare class TimeoutPromise<T> extends PromisEBase<T> implements IPromisE_Timeout<T> {
|
|
878
|
+
readonly data: IPromisE<T>;
|
|
879
|
+
readonly options: TimeoutOptions;
|
|
880
|
+
readonly timeout: IPromisE_Delay<T>;
|
|
881
|
+
readonly started: Date;
|
|
882
|
+
private _signals?;
|
|
883
|
+
constructor(data: IPromisE<T>, timeout: IPromisE_Delay<T>, options: TimeoutOptions, _signals?: AbortSignal[]);
|
|
884
|
+
get abortCtrl(): AbortController | undefined;
|
|
885
|
+
get aborted(): boolean;
|
|
886
|
+
cancelAbort(): void;
|
|
887
|
+
clearTimeout(): void;
|
|
888
|
+
get timedout(): boolean;
|
|
889
|
+
private _setup;
|
|
890
|
+
private _handleAbort;
|
|
891
|
+
private _handleEarlyFinalize;
|
|
892
|
+
private _handleFinalize;
|
|
893
|
+
static defaults: TimeoutOptionsDefault;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
export { type BatchFuncs, type DeferredAsyncCallback, type DeferredAsyncDefaults, type DeferredAsyncOptions, type GetPromiseFunc, type IPromisE, type IPromisE_Delay, type IPromisE_Timeout, type OnEarlyFinalize, type OnFinalize, PromisE, PromisEBase, type PromiseParams, ResolveError, ResolveIgnored, type RetryIfFunc, type RetryOptions, TIMEOUT_FALLBACK, TIMEOUT_MAX, type TimeoutOptions, type TimeoutOptionsDefault, TimeoutPromise, type TimeoutResult, PromisE as default, deferred, deferredCallback, delay, delayReject, retry, timeout };
|
package/dist/index.js
CHANGED
|
@@ -17,10 +17,16 @@ var _PromisEBase = class _PromisEBase extends Promise {
|
|
|
17
17
|
_reject = (reason) => {
|
|
18
18
|
reject(reason);
|
|
19
19
|
this._state = 2;
|
|
20
|
+
this.onFinalize.forEach(
|
|
21
|
+
(fn) => fallbackIfFails(fn, [void 0, reason], void 0)
|
|
22
|
+
);
|
|
20
23
|
};
|
|
21
24
|
_resolve = (value) => {
|
|
22
25
|
resolve(value);
|
|
23
26
|
this._state = 1;
|
|
27
|
+
this.onFinalize.forEach(
|
|
28
|
+
(fn) => fallbackIfFails(fn, [value, void 0], void 0)
|
|
29
|
+
);
|
|
24
30
|
};
|
|
25
31
|
if (isFn(input)) {
|
|
26
32
|
fallbackIfFails(input, [_resolve, _reject], _reject);
|
|
@@ -34,6 +40,7 @@ var _PromisEBase = class _PromisEBase extends Promise {
|
|
|
34
40
|
/**
|
|
35
41
|
* callbacks to be invoked whenever PromisE instance is finalized early using non-static resolve()/reject() methods */
|
|
36
42
|
this.onEarlyFinalize = [];
|
|
43
|
+
this.onFinalize = [];
|
|
37
44
|
//
|
|
38
45
|
//
|
|
39
46
|
// --------------------------- Early resolve/reject ---------------------------
|
|
@@ -87,11 +94,6 @@ var _PromisEBase = class _PromisEBase extends Promise {
|
|
|
87
94
|
get state() {
|
|
88
95
|
return this._state;
|
|
89
96
|
}
|
|
90
|
-
// static withResolvers = <T = unknown>() => {
|
|
91
|
-
// const pwr = globalThis.Promise.withResolvers<T>()
|
|
92
|
-
// const promise = new PromisEBase<T>(pwr.promise) as IPromisE<T>
|
|
93
|
-
// return { ...pwr, promise }
|
|
94
|
-
// }
|
|
95
97
|
};
|
|
96
98
|
//
|
|
97
99
|
//
|
|
@@ -108,8 +110,8 @@ _PromisEBase.any = (values) => new _PromisEBase(globalThis.Promise.any(values));
|
|
|
108
110
|
_PromisEBase.race = (values) => new _PromisEBase(globalThis.Promise.race(values));
|
|
109
111
|
/** Extends Promise.reject */
|
|
110
112
|
_PromisEBase.reject = (reason) => {
|
|
111
|
-
const
|
|
112
|
-
queueMicrotask(() => reject(reason));
|
|
113
|
+
const promise = new _PromisEBase();
|
|
114
|
+
queueMicrotask(() => promise.reject(reason));
|
|
113
115
|
return promise;
|
|
114
116
|
};
|
|
115
117
|
/** Sugar for `new PromisE(Promise.resolve(...))` */
|
|
@@ -312,23 +314,28 @@ var deferredCallback_default = deferredCallback;
|
|
|
312
314
|
|
|
313
315
|
// src/delay.ts
|
|
314
316
|
import { fallbackIfFails as fallbackIfFails3, isFn as isFn3 } from "@superutils/core";
|
|
315
|
-
function delay(duration = delay.defaults.duration, result
|
|
317
|
+
function delay(duration = delay.defaults.duration, result, asRejected = false) {
|
|
316
318
|
const promise = new PromisEBase_default();
|
|
317
319
|
const finalize = (result2) => {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
320
|
+
const _result = fallbackIfFails3(
|
|
321
|
+
async () => {
|
|
322
|
+
const _result2 = await (isFn3(result2) ? result2() : result2);
|
|
323
|
+
return !asRejected ? _result2 != null ? _result2 : duration : _result2 != null ? _result2 : new Error(
|
|
324
|
+
`${delay.defaults.delayTimeoutMsg} ${duration}ms`
|
|
325
|
+
);
|
|
326
|
+
},
|
|
327
|
+
[],
|
|
328
|
+
// when result is a function and it fails/rejects,
|
|
329
|
+
// promise will reject even if `asRejected = false`
|
|
330
|
+
(err) => Promise.reject(err)
|
|
326
331
|
);
|
|
332
|
+
!asRejected ? promise.resolve(_result) : _result.then(promise.reject, promise.reject);
|
|
327
333
|
};
|
|
328
334
|
promise.timeoutId = setTimeout(() => finalize(result), duration);
|
|
329
335
|
promise.pause = () => clearTimeout(promise.timeoutId);
|
|
330
336
|
promise.catch(() => {
|
|
331
337
|
}).finally(() => promise.pause());
|
|
338
|
+
promise.onEarlyFinalize.push(() => promise.pause());
|
|
332
339
|
return promise;
|
|
333
340
|
}
|
|
334
341
|
delay.defaults = {
|
|
@@ -411,45 +418,141 @@ retry.defaults = {
|
|
|
411
418
|
};
|
|
412
419
|
var retry_default = retry;
|
|
413
420
|
|
|
414
|
-
// src/
|
|
415
|
-
import {
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
421
|
+
// src/TimeoutPromise.ts
|
|
422
|
+
import { arrUnique, fallbackIfFails as fallbackIfFails5, isObj } from "@superutils/core";
|
|
423
|
+
var TIMEOUT_FALLBACK = 1e4;
|
|
424
|
+
var TIMEOUT_MAX = 2147483647;
|
|
425
|
+
var TimeoutPromise = class extends PromisEBase_default {
|
|
426
|
+
constructor(data, timeout2, options, _signals) {
|
|
427
|
+
super(data);
|
|
428
|
+
this.started = /* @__PURE__ */ new Date();
|
|
429
|
+
this._setup = () => {
|
|
430
|
+
var _a, _b, _c, _d;
|
|
431
|
+
this._signals = arrUnique(
|
|
432
|
+
[(_b = (_a = this.options) == null ? void 0 : _a.abortCtrl) == null ? void 0 : _b.signal, (_c = this.options) == null ? void 0 : _c.signal].filter(
|
|
433
|
+
Boolean
|
|
434
|
+
)
|
|
435
|
+
);
|
|
436
|
+
!this.onEarlyFinalize.includes(this._handleEarlyFinalize) && this.onEarlyFinalize.push(this._handleEarlyFinalize);
|
|
437
|
+
!this.onFinalize.includes(this._handleFinalize) && this.onFinalize.push(this._handleFinalize);
|
|
438
|
+
(_d = this._signals) == null ? void 0 : _d.forEach(
|
|
439
|
+
(signal) => signal == null ? void 0 : signal.addEventListener(
|
|
440
|
+
"abort",
|
|
441
|
+
this._handleAbort
|
|
442
|
+
)
|
|
443
|
+
);
|
|
444
|
+
};
|
|
445
|
+
this._handleAbort = async () => {
|
|
446
|
+
var _a, _b, _c;
|
|
447
|
+
if (!((_a = this._signals) == null ? void 0 : _a.length) || !this.pending) return;
|
|
448
|
+
let err = await fallbackIfFails5((_b = this.options) == null ? void 0 : _b.onAbort, [], void 0);
|
|
449
|
+
err != null ? err : err = new Error(
|
|
450
|
+
`Aborted after ${(/* @__PURE__ */ new Date()).getTime() - this.started.getTime()}ms`
|
|
451
|
+
);
|
|
452
|
+
(_c = err.name) != null ? _c : err.name = "AbortError";
|
|
453
|
+
this.reject(err);
|
|
454
|
+
};
|
|
455
|
+
this._handleEarlyFinalize = () => {
|
|
456
|
+
var _a, _b, _c, _d;
|
|
457
|
+
((_a = this.options) == null ? void 0 : _a.abortOnEarlyFinalize) && ((_d = (_c = (_b = this.options) == null ? void 0 : _b.abortCtrl) == null ? void 0 : _c.abort) == null ? void 0 : _d.call(_c));
|
|
458
|
+
};
|
|
459
|
+
// cleanup after execution
|
|
460
|
+
this._handleFinalize = ((_, err) => {
|
|
461
|
+
var _a, _b, _c, _d, _e;
|
|
462
|
+
const failed = !this.timeout.rejected && !((_a = this._signals) == null ? void 0 : _a.find((x) => x == null ? void 0 : x.aborted));
|
|
463
|
+
if (failed) return;
|
|
464
|
+
((_d = (_c = (_b = this.options) == null ? void 0 : _b.abortCtrl) == null ? void 0 : _c.signal) == null ? void 0 : _d.aborted) === false && ((_e = this.options) == null ? void 0 : _e.abortCtrl.abort(err));
|
|
465
|
+
this.cancelAbort();
|
|
466
|
+
this.clearTimeout();
|
|
467
|
+
});
|
|
468
|
+
this.data = data;
|
|
469
|
+
this.options = isObj(options) ? options : {};
|
|
470
|
+
this.timeout = timeout2;
|
|
471
|
+
this._signals = _signals;
|
|
472
|
+
this._setup();
|
|
473
|
+
}
|
|
474
|
+
get abortCtrl() {
|
|
475
|
+
return this.options.abortCtrl;
|
|
476
|
+
}
|
|
477
|
+
get aborted() {
|
|
478
|
+
var _a;
|
|
479
|
+
return this.rejected && !this.timeout.rejected && !!((_a = this._signals) == null ? void 0 : _a.find((s) => s == null ? void 0 : s.aborted));
|
|
480
|
+
}
|
|
481
|
+
cancelAbort() {
|
|
482
|
+
var _a;
|
|
483
|
+
(_a = this._signals) == null ? void 0 : _a.forEach(
|
|
484
|
+
(signal) => signal == null ? void 0 : signal.removeEventListener(
|
|
485
|
+
"abort",
|
|
486
|
+
this._handleAbort
|
|
487
|
+
)
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
clearTimeout() {
|
|
491
|
+
clearTimeout(this.timeout.timeoutId);
|
|
492
|
+
}
|
|
493
|
+
get timedout() {
|
|
494
|
+
return this.rejected && this.timeout.rejected;
|
|
424
495
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
496
|
+
};
|
|
497
|
+
TimeoutPromise.defaults = {
|
|
498
|
+
abortOnEarlyFinalize: true,
|
|
499
|
+
batchFunc: "all",
|
|
500
|
+
timeout: TIMEOUT_FALLBACK
|
|
501
|
+
};
|
|
502
|
+
var TimeoutPromise_default = TimeoutPromise;
|
|
503
|
+
|
|
504
|
+
// src/timeout.ts
|
|
505
|
+
import {
|
|
506
|
+
arrUnique as arrUnique2,
|
|
507
|
+
isFn as isFn4,
|
|
508
|
+
isNumber,
|
|
509
|
+
isObj as isObj2,
|
|
510
|
+
isPositiveNumber as isPositiveNumber2,
|
|
511
|
+
objCopy as objCopy3
|
|
512
|
+
} from "@superutils/core";
|
|
513
|
+
function timeout(options, ...values) {
|
|
514
|
+
var _a;
|
|
515
|
+
const opts = objCopy3(
|
|
516
|
+
timeout.defaults,
|
|
517
|
+
isNumber(options) ? { timeout: options } : isObj2(options) ? options : {},
|
|
518
|
+
[],
|
|
519
|
+
"empty"
|
|
520
|
+
);
|
|
521
|
+
opts.timeout = Math.min(
|
|
522
|
+
isPositiveNumber2(opts.timeout) ? opts.timeout : TIMEOUT_FALLBACK,
|
|
523
|
+
TIMEOUT_MAX
|
|
524
|
+
);
|
|
525
|
+
const promises = values.map(
|
|
526
|
+
(v) => isFn4(v) ? PromisEBase_default.try(v) : v
|
|
527
|
+
);
|
|
528
|
+
const dataPromise = promises.length <= 1 ? (
|
|
529
|
+
// single promise resolves to a single result
|
|
530
|
+
promises[0] instanceof PromisEBase_default ? promises[0] : new PromisEBase_default(promises[0])
|
|
531
|
+
) : (
|
|
532
|
+
// multiple promises resolve to an array of results
|
|
533
|
+
(isFn4(PromisEBase_default[opts.batchFunc]) ? PromisEBase_default[opts.batchFunc] : PromisEBase_default.all)(promises)
|
|
534
|
+
);
|
|
535
|
+
const timeoutPromise = delayReject_default(opts.timeout, opts.onTimeout);
|
|
536
|
+
const promise = new TimeoutPromise_default(
|
|
537
|
+
PromisEBase_default.race([dataPromise, timeoutPromise]),
|
|
538
|
+
timeoutPromise,
|
|
539
|
+
opts,
|
|
540
|
+
arrUnique2(
|
|
541
|
+
[(_a = opts.abortCtrl) == null ? void 0 : _a.signal, opts.signal].filter(Boolean)
|
|
542
|
+
)
|
|
431
543
|
);
|
|
432
|
-
const promise = PromisEBase_default.race([
|
|
433
|
-
dataPromise,
|
|
434
|
-
timeoutPromise
|
|
435
|
-
]);
|
|
436
|
-
promise.clearTimeout = () => clearTimeout(timeoutPromise.timeoutId);
|
|
437
|
-
promise.data = dataPromise;
|
|
438
|
-
promise.timeout = timeoutPromise;
|
|
439
|
-
Object.defineProperty(promise, "timedout", {
|
|
440
|
-
get: () => promise.timeout.rejected
|
|
441
|
-
});
|
|
442
|
-
dataPromise.catch(() => {
|
|
443
|
-
}).finally(() => {
|
|
444
|
-
promise.clearTimeout();
|
|
445
|
-
});
|
|
446
544
|
return promise;
|
|
447
545
|
}
|
|
448
|
-
timeout.defaultOptions = {
|
|
449
|
-
func: "all",
|
|
450
|
-
timeout: 1e4
|
|
451
|
-
};
|
|
452
546
|
var timeout_default = timeout;
|
|
547
|
+
timeout.defaults = TimeoutPromise_default.defaults;
|
|
548
|
+
Object.defineProperty(timeout, "defaults", {
|
|
549
|
+
get() {
|
|
550
|
+
return TimeoutPromise_default.defaults;
|
|
551
|
+
},
|
|
552
|
+
set(newDefaults) {
|
|
553
|
+
TimeoutPromise_default.defaults = newDefaults;
|
|
554
|
+
}
|
|
555
|
+
});
|
|
453
556
|
|
|
454
557
|
// src/PromisE.ts
|
|
455
558
|
var PromisE = class extends PromisEBase_default {
|
|
@@ -469,6 +572,9 @@ export {
|
|
|
469
572
|
PromisEBase,
|
|
470
573
|
ResolveError,
|
|
471
574
|
ResolveIgnored,
|
|
575
|
+
TIMEOUT_FALLBACK,
|
|
576
|
+
TIMEOUT_MAX,
|
|
577
|
+
TimeoutPromise,
|
|
472
578
|
index_default as default,
|
|
473
579
|
deferred,
|
|
474
580
|
deferredCallback,
|
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.1
|
|
7
|
+
"@superutils/core": "^1.2.1"
|
|
8
8
|
},
|
|
9
9
|
"description": "An extended Promise with additional 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.
|
|
26
|
+
"@superutils/core": "^1.2.0"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|
|
@@ -43,5 +43,6 @@
|
|
|
43
43
|
"sideEffects": false,
|
|
44
44
|
"type": "module",
|
|
45
45
|
"types": "dist/index.d.ts",
|
|
46
|
-
"version": "1.1
|
|
46
|
+
"version": "1.2.1",
|
|
47
|
+
"gitHead": "a26f4b1bb701d99d4cb71443e18680ee3ea52974"
|
|
47
48
|
}
|