@oazmi/superbuild 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/_dnt.shims.d.ts +2 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +57 -0
- package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.d.ts +598 -0
- package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/esbuild-types/0.28.0/src/mod.js +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.d.ts +617 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/alias.js +671 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.d.ts +487 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array1d.js +536 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.d.ts +266 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/array2d.js +318 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.d.ts +368 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/binder.js +380 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.d.ts +711 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/crossenv.js +1173 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.d.ts +171 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/cryptoman.js +308 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.d.ts +10 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/deps.js +10 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.d.ts +168 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack.js +236 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.d.ts +90 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/eightpack_varint.js +237 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.d.ts +213 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericarray.js +363 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.d.ts +233 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/numericmethods.js +256 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.d.ts +1436 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/pathman.js +1730 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.d.ts +647 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.js +762 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.d.ts +538 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/stringman.js +626 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.d.ts +734 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/struct.js +764 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.d.ts +137 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedbuffer.js +234 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.d.ts +391 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.d.ts.map +1 -0
- package/esm/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/typedefs.js +8 -0
- package/esm/deps.d.ts +56 -0
- package/esm/deps.d.ts.map +1 -0
- package/esm/deps.js +37 -0
- package/esm/esbuild/metafile.d.ts +90 -0
- package/esm/esbuild/metafile.d.ts.map +1 -0
- package/esm/esbuild/metafile.js +275 -0
- package/esm/esbuild/native.d.ts +95 -0
- package/esm/esbuild/native.d.ts.map +1 -0
- package/esm/esbuild/native.js +127 -0
- package/esm/esbuild/outputfile.d.ts +86 -0
- package/esm/esbuild/outputfile.d.ts.map +1 -0
- package/esm/esbuild/outputfile.js +221 -0
- package/esm/esbuild/strongtypes.d.ts +90 -0
- package/esm/esbuild/strongtypes.d.ts.map +1 -0
- package/esm/esbuild/strongtypes.js +8 -0
- package/esm/esbuild/typedefs.d.ts +121 -0
- package/esm/esbuild/typedefs.d.ts.map +1 -0
- package/esm/esbuild/typedefs.js +55 -0
- package/esm/esbuild/weaktypes.d.ts +46 -0
- package/esm/esbuild/weaktypes.d.ts.map +1 -0
- package/esm/esbuild/weaktypes.js +8 -0
- package/esm/funcdefs.d.ts +89 -0
- package/esm/funcdefs.d.ts.map +1 -0
- package/esm/funcdefs.js +145 -0
- package/esm/mod.d.ts +4 -0
- package/esm/mod.d.ts.map +1 -0
- package/esm/mod.js +2 -0
- package/esm/package.json +3 -0
- package/esm/plugins/emissions_driver.d.ts +33 -0
- package/esm/plugins/emissions_driver.d.ts.map +1 -0
- package/esm/plugins/emissions_driver.js +260 -0
- package/esm/plugins/long_build.d.ts +138 -0
- package/esm/plugins/long_build.d.ts.map +1 -0
- package/esm/plugins/long_build.js +288 -0
- package/esm/plugins/native_replica.d.ts +48 -0
- package/esm/plugins/native_replica.d.ts.map +1 -0
- package/esm/plugins/native_replica.js +122 -0
- package/esm/super/build.d.ts +53 -0
- package/esm/super/build.d.ts.map +1 -0
- package/esm/super/build.js +39 -0
- package/esm/super/build_context.d.ts +83 -0
- package/esm/super/build_context.d.ts.map +1 -0
- package/esm/super/build_context.js +124 -0
- package/esm/super/mod.d.ts +12 -0
- package/esm/super/mod.d.ts.map +1 -0
- package/esm/super/mod.js +9 -0
- package/esm/super/plugin.d.ts +23 -0
- package/esm/super/plugin.d.ts.map +1 -0
- package/esm/super/plugin.js +31 -0
- package/esm/super/plugin_build.d.ts +38 -0
- package/esm/super/plugin_build.d.ts.map +1 -0
- package/esm/super/plugin_build.js +198 -0
- package/esm/super/typedefs.d.ts +323 -0
- package/esm/super/typedefs.d.ts.map +1 -0
- package/esm/super/typedefs.js +10 -0
- package/esm/typedefs.d.ts +21 -0
- package/esm/typedefs.d.ts.map +1 -0
- package/esm/typedefs.js +5 -0
- package/license.md +37 -0
- package/package.json +88 -0
- package/readme.md +181 -0
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
/** this submodule contains _promise_, _task_, and _scheduling_ related utility functions.
|
|
2
|
+
*
|
|
3
|
+
* @module
|
|
4
|
+
*/
|
|
5
|
+
import type { MaybePromise, MaybePromiseLike, PromiseResolver } from "./typedefs.js";
|
|
6
|
+
/** this is a re-export of {@link promise_outside}.
|
|
7
|
+
*
|
|
8
|
+
* {@inheritDoc promise_outside}
|
|
9
|
+
*/
|
|
10
|
+
export declare const promiseOutside: <T>() => [promise: Promise<T>, resolve: (value: MaybePromiseLike<T>) => void, reject: (reason?: any) => void];
|
|
11
|
+
/** a promise that resolves (or rejects if `should_reject = true`) after a certain number of milliseconds.
|
|
12
|
+
*
|
|
13
|
+
* this is a useful shorthand for creating delays, and then following them up with a `.then` call.
|
|
14
|
+
* you may also use this as a sleep/wait function in an async context where `await` is available.
|
|
15
|
+
*/
|
|
16
|
+
export declare const promiseTimeout: (wait_time_ms: number, should_reject?: boolean) => Promise<typeof TIMEOUT>;
|
|
17
|
+
/** configuration options for the {@link scheduleTimeout} function. */
|
|
18
|
+
export interface ScheduleTimeoutConfig {
|
|
19
|
+
/** when the timeout occurs, should the promise be rejected?
|
|
20
|
+
*
|
|
21
|
+
* @defaultValue `false` (i.e. the timeout promise will be resolved with the value {@link TIMEOUT}, rather than being rejected)
|
|
22
|
+
*/
|
|
23
|
+
reject?: boolean;
|
|
24
|
+
/** when the current time is greater than the specified `epoch_time_ms`
|
|
25
|
+
* (i.e. `Date.now() > epoch_time_ms`), we call that task _expired_.
|
|
26
|
+
*
|
|
27
|
+
* this option lets you specify what action should be taken when a task is expired:
|
|
28
|
+
*
|
|
29
|
+
* - `true`: resolve/reject the promise immediately (based on the {@link reject} option), with the default return value ({@link TIMEOUT}).
|
|
30
|
+
* - `false`: keep the promise hanging forever; never to be resolved nor rejected.
|
|
31
|
+
* - `"resolve"`: resolve the promise immediately (irrespective of the {@link reject} option), with the default return value ({@link TIMEOUT}).
|
|
32
|
+
* - `"reject"`: reject the promise immediately (irrespective of the {@link reject} option), with the default reject value ({@link TIMEOUT}).
|
|
33
|
+
* - `(() => (boolean | "resolve" | "reject"))`: run a callback function that returns one of the prior specified actions that can be taken.
|
|
34
|
+
*
|
|
35
|
+
* @defaultValue `true`
|
|
36
|
+
*/
|
|
37
|
+
runExpired?: boolean | "resolve" | "reject" | (() => (boolean | "resolve" | "reject"));
|
|
38
|
+
}
|
|
39
|
+
/** schedule a promise that resolves when a specific local epoch-time (based on `Date.now()`) is reached.
|
|
40
|
+
*
|
|
41
|
+
* see what configuration options are available to you in {@link ScheduleTimeoutConfig}.
|
|
42
|
+
*
|
|
43
|
+
* // TODO: add tests maybe?
|
|
44
|
+
*/
|
|
45
|
+
export declare const scheduleTimeout: (epoch_time_ms: number, config?: ScheduleTimeoutConfig) => Promise<typeof TIMEOUT>;
|
|
46
|
+
/** a special symbol that signifies when a throttle function
|
|
47
|
+
* (such as {@link throttle} and {@link throttleAndTrail})
|
|
48
|
+
* has rejected to run a function, due to calling rate throttling.
|
|
49
|
+
*/
|
|
50
|
+
export declare const THROTTLE_REJECT: unique symbol;
|
|
51
|
+
/** a special symbol that signifies when a timeout function (such as {@link promiseTimeout}) has timed out. */
|
|
52
|
+
export declare const TIMEOUT: unique symbol;
|
|
53
|
+
/** creates a debounced version of the provided function that returns a new promise.
|
|
54
|
+
*
|
|
55
|
+
* the debounced function delays the execution of the provided function `fn` until the debouncing interval `wait_time_ms` amount of time has passed without any subsequent calls.
|
|
56
|
+
*
|
|
57
|
+
* if a `rejection_value` is provided, then any subsequent calls to the debounced function that are made within the debouncing interval, will reject the previous promises.
|
|
58
|
+
* thus you will have to `catch` them in that case (otherwise it will result in an error).
|
|
59
|
+
*
|
|
60
|
+
* you may worry that too many calls to a non-rejectable debounced function (i.e. when `rejection_value === undefined`)
|
|
61
|
+
* will create too many promise objects, possibly resulting in memory leaks.
|
|
62
|
+
* however, luckily, modern javascript engines are not afflicted by too many pending promise objects.
|
|
63
|
+
* in fact, choosing to reject promises (i.e. by setting `rejection_value`), might be more expensive down the line, as error catching is typically expensive.
|
|
64
|
+
*
|
|
65
|
+
* also check out {@link debounceAndShare}, which avoids this "lots of promise objects" issue by sharing the same promise across all quick callers of the debounce.
|
|
66
|
+
* but it will require careful usage, as all promised callers will eventually get resolved, which may create an unintended avalaunch of subsequent `then` calls if not used carefully.
|
|
67
|
+
*
|
|
68
|
+
* @param wait_time_ms the time interval in milliseconds for debouncing
|
|
69
|
+
* @param fn the function to be debounced
|
|
70
|
+
* @param rejection_value if a rejection value is provided, then old unresolved pending promises will be rejected with the given value,
|
|
71
|
+
* when a new call to the debounced function is made (within the debouncing waiting period)
|
|
72
|
+
* @returns a function (that takes arguments intended for `fn`) that returns a promise, which is resolved once `wait_time_ms` amount of time has passed with no further calls
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* import {
|
|
77
|
+
* assertEquals as assertEq,
|
|
78
|
+
* assertLessOrEqual as assertLe,
|
|
79
|
+
* assertGreaterOrEqual as assertGe,
|
|
80
|
+
* } from "jsr:@std/assert"
|
|
81
|
+
*
|
|
82
|
+
* // a function that creates an asynchronous delay of the given number of milliseconds
|
|
83
|
+
* const sleep = (time_ms: number) => (new Promise((resolve) => (setTimeout(resolve, time_ms))))
|
|
84
|
+
*
|
|
85
|
+
* const
|
|
86
|
+
* log_history: Array<[time: number, value: number]> = [],
|
|
87
|
+
* error_history: Array<[time: number, message: string]> = [],
|
|
88
|
+
* t0 = performance.now(),
|
|
89
|
+
* current_time = () => (performance.now() - t0)
|
|
90
|
+
*
|
|
91
|
+
* // the function that we plan to debounce
|
|
92
|
+
* const fn = (v: number) => {
|
|
93
|
+
* log_history.push([current_time(), v])
|
|
94
|
+
* return v + 100
|
|
95
|
+
* }
|
|
96
|
+
*
|
|
97
|
+
* // the debounced version of `fn`, that, when called too quickly, rejects with the reason `"SEPPUKU!"`.
|
|
98
|
+
* const debounced_fn = debounce(1000, fn, "SEPPUKU!")
|
|
99
|
+
*
|
|
100
|
+
* // `a` is a promise that should resolve after 1000ms. but if it fails (which it will), it will log to `error_history`.
|
|
101
|
+
* const a = debounced_fn(24).catch(
|
|
102
|
+
* (reason) => { error_history.push([current_time(), `they want me to ${reason}`]) }
|
|
103
|
+
* )
|
|
104
|
+
*
|
|
105
|
+
* await sleep(500) // promise `a` is still pending after the 500ms sleep
|
|
106
|
+
*
|
|
107
|
+
* // the new `debounced_fn(42)` below rejects `a`'s promise, and then returns a new promise (`b`) that will resolve in 1000ms.
|
|
108
|
+
* // since `a` gets rejected as a consequence, it's error handling chain will immediately log `"they want me to SEPPUKU!"` in the console.
|
|
109
|
+
* const b = debounced_fn(42)
|
|
110
|
+
*
|
|
111
|
+
* // we delay for a tiny while in order for the js-runtime to get `a` rejected. otherwise, without the sleep, `error_history` will be empty.
|
|
112
|
+
* await sleep(50)
|
|
113
|
+
* assertEq(log_history, [])
|
|
114
|
+
* assertGe(error_history[0][0], 499)
|
|
115
|
+
* assertLe(error_history[0][0], 540)
|
|
116
|
+
* assertEq(error_history[0][1], "they want me to SEPPUKU!")
|
|
117
|
+
*
|
|
118
|
+
* // after 1000ms, the value `42` will be logged into `log_history` (due to promise `b`).
|
|
119
|
+
* // however, no entry will be logged by `a`, since it gets rejected as soon as `b` is created.
|
|
120
|
+
* await sleep(1000)
|
|
121
|
+
* assertGe(log_history[0][0], 500 + 999)
|
|
122
|
+
* assertLe(log_history[0][0], 500 + 1040)
|
|
123
|
+
* assertEq(log_history[0][1], 42)
|
|
124
|
+
* assertEq(await b, 100 + 42)
|
|
125
|
+
*
|
|
126
|
+
* // we can now safely create a new debounced call without rejecting the already resolved `b` promise, since it is over 1000ms since `b` was created.
|
|
127
|
+
* const c = debounced_fn(99)
|
|
128
|
+
*
|
|
129
|
+
* // 1000ms later, the value `99` will be logged into `log_history` (due to promise `c`).
|
|
130
|
+
* await sleep(1050)
|
|
131
|
+
* assertGe(log_history[1][0], 1550 + 999)
|
|
132
|
+
* assertLe(log_history[1][0], 1550 + 1100)
|
|
133
|
+
* assertEq(log_history[1][1], 99)
|
|
134
|
+
* assertEq(await c, 100 + 99)
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export declare const debounce: <T extends unknown, ARGS extends any[], REJ>(wait_time_ms: number, fn: (...args: ARGS) => T, rejection_value?: REJ) => ((...args: ARGS) => Promise<T>);
|
|
138
|
+
/** creates a debounced version of the provided function that returns a shared promise.
|
|
139
|
+
*
|
|
140
|
+
* unlike conventional {@link debounce}, this function reuses and returns the same promise object for all calls that are made within the debouncing interval.
|
|
141
|
+
* this means that all callers within this interval will receive the same promise, which will be resolved once `wait_time_ms` amount of time has passed with no further calls.
|
|
142
|
+
*
|
|
143
|
+
* if subsequent calls are made within the debouncing interval, the debounced function will return the same promise as before, further delaying its resolution.
|
|
144
|
+
* however, once the debouncing interval has elapsed and the promise is resolved, any new calls to the debounced function will create and return a new promise.
|
|
145
|
+
*
|
|
146
|
+
* @param wait_time_ms the time interval in milliseconds for debouncing
|
|
147
|
+
* @param fn the function to be debounced
|
|
148
|
+
* @returns a function (that takes arguments intended for `fn`) that returns a promise, which is resolved once `wait_time_ms` amount of time has passed with no further calls
|
|
149
|
+
*
|
|
150
|
+
* @example
|
|
151
|
+
* ```ts
|
|
152
|
+
* import {
|
|
153
|
+
* assertEquals as assertEq,
|
|
154
|
+
* assertLessOrEqual as assertLe,
|
|
155
|
+
* assertGreaterOrEqual as assertGe,
|
|
156
|
+
* } from "jsr:@std/assert"
|
|
157
|
+
*
|
|
158
|
+
* // a function that creates an asynchronous delay of the given number of milliseconds
|
|
159
|
+
* const sleep = (time_ms: number) => (new Promise((resolve) => (setTimeout(resolve, time_ms))))
|
|
160
|
+
*
|
|
161
|
+
* const
|
|
162
|
+
* log_history: Array<[time: number, value: number]> = [],
|
|
163
|
+
* t0 = performance.now(),
|
|
164
|
+
* current_time = () => (performance.now() - t0)
|
|
165
|
+
*
|
|
166
|
+
* // the function that we plan to apply shareable-debouncing to
|
|
167
|
+
* const fn = (v: number) => {
|
|
168
|
+
* log_history.push([current_time(), v])
|
|
169
|
+
* return v + 100
|
|
170
|
+
* }
|
|
171
|
+
*
|
|
172
|
+
* // the debounced version of `fn`, that, when called too quickly, shares the existing promise, and prolongs its resolution by the wait time
|
|
173
|
+
* const debounced_fn = debounceAndShare(1000, fn)
|
|
174
|
+
*
|
|
175
|
+
* // `a` is a promise that should resolve after 1000ms since the last interruption call to `debounced_fn` (i.e. 1000ms from now).
|
|
176
|
+
* const a = debounced_fn(24)
|
|
177
|
+
*
|
|
178
|
+
* await sleep(500) // promise `a` is still pending after the 500ms sleep
|
|
179
|
+
*
|
|
180
|
+
* // since `a` has not been resolved yet, calling `debounced_fn` again to construct `b` will result in the reusage of the old existing promise `a`.
|
|
181
|
+
* // in addition, due to the interuptive call, the resolution of the `a` and `b` promises will be delayed by another 1000ms from here on.
|
|
182
|
+
* const b = debounced_fn(42)
|
|
183
|
+
*
|
|
184
|
+
* assertEq(a === b, true) // the promises `a` and `b` are one and the same, since `debounced_fn` shares the existing non-settled promises.
|
|
185
|
+
*
|
|
186
|
+
* // after the sleep below, 1050ms would have passed since the creation of `a`, and it would have been resolved had we _not_ created `b`.
|
|
187
|
+
* // however, since we created `b` within the debounce interval of 1000ms, the promise's timer has been reset.
|
|
188
|
+
* await sleep(550)
|
|
189
|
+
* assertEq(log_history, [])
|
|
190
|
+
*
|
|
191
|
+
* // 1000ms after the creation of `b`, the value `42` will be logged into `log_history` (due to promise `a` and `b`).
|
|
192
|
+
* await sleep(500)
|
|
193
|
+
* assertGe(log_history[0][0], 500 + 999)
|
|
194
|
+
* assertLe(log_history[0][0], 500 + 1040)
|
|
195
|
+
* assertEq(log_history[0][1], 42)
|
|
196
|
+
* assertEq(await a, 100 + 42) // notice that the value of `a` has changed to the expected output value of `b`, because they are one and the same.
|
|
197
|
+
* assertEq(await b, 100 + 42)
|
|
198
|
+
*
|
|
199
|
+
* // now that promises `a` and `b` have been resolved, executing the shared-debounced function again will create a new promise that will resolve after 1000ms from now.
|
|
200
|
+
* const c = debounced_fn(99)
|
|
201
|
+
* assertEq(c === b, false)
|
|
202
|
+
*
|
|
203
|
+
* // 1000ms later, the value `99` will be logged into `log_history` (due to promise `c`).
|
|
204
|
+
* await sleep(1050)
|
|
205
|
+
* assertGe(log_history[1][0], 1550 + 999)
|
|
206
|
+
* assertLe(log_history[1][0], 1550 + 1100)
|
|
207
|
+
* assertEq(log_history[1][1], 99)
|
|
208
|
+
* assertEq(await c, 100 + 99)
|
|
209
|
+
*
|
|
210
|
+
* // key takeaway:
|
|
211
|
+
* // - notice that the promises made within the debounce interval are the same pomise objects (i.e. `a === b`).
|
|
212
|
+
* // - however, once out of that interval, an entirely new promise is generated (i.e. `b !== c`)
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
215
|
+
export declare const debounceAndShare: <T extends unknown, ARGS extends any[]>(wait_time_ms: number, fn: (...args: ARGS) => T) => ((...args: ARGS) => Promise<T>);
|
|
216
|
+
/** a throttled function blocks the execution of `fn`, if less than `delta_time_ms` amount of time has passed since the previous non-rejected call.
|
|
217
|
+
* a rejected caller would receive the {@link THROTTLE_REJECT} symbol, instead of the `fn` function's evaluated value.
|
|
218
|
+
*
|
|
219
|
+
* ### Visualization
|
|
220
|
+
*
|
|
221
|
+
* the following visual illustration should give you an idea of how a throttled function with `delta_time_ms = 1000` would behave.
|
|
222
|
+
* - the intersections in the `call made` axis specifies the time where a call is made to the throttled function.
|
|
223
|
+
* - successfully evaluated calls are labeled as `resolved` (with the legend marker `o`), and their caller will receive the evaluated value of `fn()`
|
|
224
|
+
* - unsuccessful calls (i.e. rejected) are labeled as `rejected` (with the legend marker `x`), and their caller will receive the symbol value {@link THROTTLE_REJECT}.
|
|
225
|
+
*
|
|
226
|
+
* ```text
|
|
227
|
+
* │resolved │ o o o
|
|
228
|
+
* │rejected │ │ x x x │ x │ x x
|
|
229
|
+
* │call made├──┴─┴──┴─┴──┴─┴────────────────┴─┴─┴─────────────────► time
|
|
230
|
+
* │time │ 0 1 2 3 4 5
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* @param delta_time_ms the time interval in milliseconds for throttling
|
|
234
|
+
* @param fn the function to be throttled
|
|
235
|
+
* @returns a function (that takes arguments intended for `fn`) that returns the value of `fn` if it was not throttled,
|
|
236
|
+
* otherwise a {@link THROTTLE_REJECT} symbol is returned.
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```ts
|
|
240
|
+
* import {
|
|
241
|
+
* assertEquals as assertEq,
|
|
242
|
+
* assertLessOrEqual as assertLe,
|
|
243
|
+
* assertGreaterOrEqual as assertGe,
|
|
244
|
+
* } from "jsr:@std/assert"
|
|
245
|
+
*
|
|
246
|
+
* // a function that creates an asynchronous delay of the given number of milliseconds
|
|
247
|
+
* const sleep = (time_ms: number) => (new Promise((resolve) => (setTimeout(resolve, time_ms))))
|
|
248
|
+
*
|
|
249
|
+
* const
|
|
250
|
+
* log_history: Array<[time: number, value: number]> = [],
|
|
251
|
+
* t0 = performance.now(),
|
|
252
|
+
* current_time = () => (performance.now() - t0)
|
|
253
|
+
*
|
|
254
|
+
* // the function that we plan to apply throttling to
|
|
255
|
+
* const fn = (v: number) => {
|
|
256
|
+
* log_history.push([current_time(), v])
|
|
257
|
+
* return v + 100
|
|
258
|
+
* }
|
|
259
|
+
*
|
|
260
|
+
* // the throttled version of `fn`, that blocks subsequent calls when they are made under the `delta_time` interval (1000ms here).
|
|
261
|
+
* const throttled_fn = throttle(1000, fn)
|
|
262
|
+
*
|
|
263
|
+
* // first call to the `throttled_fn` will be evaluated successfully and immediately
|
|
264
|
+
* const a = throttled_fn(24)
|
|
265
|
+
*
|
|
266
|
+
* assertEq(a, 100 + 24)
|
|
267
|
+
* assertGe(log_history[0][0], 0)
|
|
268
|
+
* assertLe(log_history[0][0], 100)
|
|
269
|
+
* assertEq(log_history[0][1], 24)
|
|
270
|
+
*
|
|
271
|
+
* // subsequent calls to the `throttled_fn` that are made under 1000ms, will be immediately rejected with the symbol value `THROTTLE_REJECT`.
|
|
272
|
+
* await sleep(200)
|
|
273
|
+
* const b1 = throttled_fn(37)
|
|
274
|
+
* const b2 = throttled_fn(42)
|
|
275
|
+
*
|
|
276
|
+
* assertEq(b1, THROTTLE_REJECT)
|
|
277
|
+
* assertEq(b2, THROTTLE_REJECT)
|
|
278
|
+
* assertGe(current_time(), 199)
|
|
279
|
+
* assertLe(current_time(), 400)
|
|
280
|
+
*
|
|
281
|
+
* // finally, when 1000ms has passed, `throttled_fn` will permit another successful call
|
|
282
|
+
* await sleep(800)
|
|
283
|
+
* const c = throttled_fn(99)
|
|
284
|
+
*
|
|
285
|
+
* assertEq(c, 100 + 99)
|
|
286
|
+
* assertGe(log_history[1][0], 999)
|
|
287
|
+
* assertLe(log_history[1][0], 1300)
|
|
288
|
+
* assertEq(log_history[1][1], 99)
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
export declare const throttle: <T extends unknown, ARGS extends any[]>(delta_time_ms: number, fn: (...args: ARGS) => T) => ((...args: ARGS) => (T | typeof THROTTLE_REJECT));
|
|
292
|
+
/** a throttle function, similar to {@link throttle}, that also insures that the **final** call (aka trailing call) made to the throttled function **always** resolves eventually.
|
|
293
|
+
*
|
|
294
|
+
* this is useful in cases where it is of utmost importance that the throttled function is called **one last time** with before a prolonged delay.
|
|
295
|
+
*
|
|
296
|
+
* ### Visualization
|
|
297
|
+
*
|
|
298
|
+
* the following visual illustration shows the difference between the regular {@link throttle}, and {@link throttleAndTrail} functions:
|
|
299
|
+
*
|
|
300
|
+
* #### this {@link throttleAndTrail} function
|
|
301
|
+
*
|
|
302
|
+
* here is a function `fn` throttled with `trailing_time_ms = 1500`, and `delta_time_ms = 1000`.
|
|
303
|
+
* as you can see below, the trailing calls to the throttled function do get resolved eventually (1500ms after the last call).
|
|
304
|
+
*
|
|
305
|
+
* ```text
|
|
306
|
+
* │time │ ╭╶╶╮ 1.2 2.7 3.3 4.8 5.2
|
|
307
|
+
* ├─────────│ ╭╶┤ │ ┌───(delayed)──┐ ┌───(delayed)──┐ (rejected)
|
|
308
|
+
* │ │ ╭╶╶┤ │ │ │ ▼ ╭╶┤ ▼ ╭╶╶╶╶╶╶╶╮
|
|
309
|
+
* │resolved │ o ▼ ▼ ▼ o │ o o ▼ │ o o ▼ o
|
|
310
|
+
* │rejected │ │ x x x │ │ │ x │ │ x │
|
|
311
|
+
* │call made├──┴─┴──┴─┴──┴─┴────────────────┴─┴─┴────────────────┴─┴───────┴──► time
|
|
312
|
+
* │time │ 0 1 2 3 4 5 6
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* #### regular {@link throttle} function
|
|
316
|
+
*
|
|
317
|
+
* here is a function `fn` throttled with `delta_time_ms = 1000`.
|
|
318
|
+
* as it can be seen below, the final call to the throttled function gets rejected, because it was called too quickly.
|
|
319
|
+
*
|
|
320
|
+
* ```text
|
|
321
|
+
* │resolved │ o o o
|
|
322
|
+
* │rejected │ │ x x x │ x │ x x
|
|
323
|
+
* │call made├──┴─┴──┴─┴──┴─┴────────────────┴─┴─┴─────────────────► time
|
|
324
|
+
* │time │ 0 1 2 3 4 5
|
|
325
|
+
* ```
|
|
326
|
+
*
|
|
327
|
+
* @param trailing_time_ms the time in milliseconds after which a trailing (pending) call to the function gets resolved if no other calls are made during that time interval.
|
|
328
|
+
* you would definitely want this to be some value greater than {@link delta_time_ms}, otherwise it will be weird because if this value is smaller,
|
|
329
|
+
* then `trailing_time_ms` will become the "effective" throttling time interval, but also one that always resolved later rather than immediately.
|
|
330
|
+
* @param delta_time_ms the time interval in milliseconds for throttling
|
|
331
|
+
* @param fn the function to be throttled
|
|
332
|
+
* @param rejection_value if a rejection value is provided, then old unresolved pending promises will be rejected with the given value,
|
|
333
|
+
* when a new call to the throttled function is made within the {@link trailing_time_ms} waiting period.
|
|
334
|
+
* if no rejection value is provided, then the promise will linger around unsettled forever.
|
|
335
|
+
* do note that having a rejection value means that you **will** have to catch any rejections if you wait for the promise,
|
|
336
|
+
* otherwise it will bubble to the top level as an unhandled error.
|
|
337
|
+
* @returns a function (that takes arguments intended for `fn`) that returns a `Promise` to the value of `fn` if it is resolved (i.e. not throttled or when trailing),
|
|
338
|
+
* otherwise if throttled, then that promise will either be never be resolved, or rejected based on if a {@link rejection_value} was provided.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```ts
|
|
342
|
+
* import {
|
|
343
|
+
* assertEquals as assertEq,
|
|
344
|
+
* assertLessOrEqual as assertLe,
|
|
345
|
+
* assertGreaterOrEqual as assertGe,
|
|
346
|
+
* } from "jsr:@std/assert"
|
|
347
|
+
*
|
|
348
|
+
* // a function that creates an asynchronous delay of the given number of milliseconds
|
|
349
|
+
* const sleep = (time_ms: number) => (new Promise((resolve) => (setTimeout(resolve, time_ms))))
|
|
350
|
+
*
|
|
351
|
+
* const
|
|
352
|
+
* log_history: Array<[time: number, value: number]> = [],
|
|
353
|
+
* t0 = performance.now(),
|
|
354
|
+
* current_time = () => (performance.now() - t0)
|
|
355
|
+
*
|
|
356
|
+
* // the function that we plan to apply throttling to
|
|
357
|
+
* const fn = (v: number) => {
|
|
358
|
+
* log_history.push([current_time(), v])
|
|
359
|
+
* return v + 100
|
|
360
|
+
* }
|
|
361
|
+
*
|
|
362
|
+
* // the throttled version of `fn` with trailing enabled.
|
|
363
|
+
* // a call is considered to be a trailing call if more than `trailing_time_ms` of 1500ms has passed since its inception.
|
|
364
|
+
* // however after a successful call, subsequent non-trailing calls made under the `delta_time` interval of 1000ms will be rejected with the value `"REJECTED!"`.
|
|
365
|
+
* const throttled_fn = throttleAndTrail(1500, 1000, fn, "REJECTED!")
|
|
366
|
+
*
|
|
367
|
+
* // first call to the `throttled_fn` will be evaluated successfully and immediately (albeit being wrapped under a promise)
|
|
368
|
+
* const a = throttled_fn(24)
|
|
369
|
+
*
|
|
370
|
+
* await sleep(100)
|
|
371
|
+
* assertGe(log_history[0][0], 0)
|
|
372
|
+
* assertLe(log_history[0][0], 100)
|
|
373
|
+
* assertEq(log_history[0][1], 24)
|
|
374
|
+
* assertEq(await a, 100 + 24)
|
|
375
|
+
*
|
|
376
|
+
* // subsequent non-trailing calls to the `throttled_fn` that are made under 1000ms, will be rejected with the custom value `"REJECTED!"`.
|
|
377
|
+
* await sleep(100)
|
|
378
|
+
* const b1 = throttled_fn(37).catch(reason => reason)
|
|
379
|
+
* const b2 = throttled_fn(42).catch(reason => reason)
|
|
380
|
+
*
|
|
381
|
+
* assertEq(await b1, "REJECTED!")
|
|
382
|
+
* // we don't await for `b2`, because after 1500ms, it will be resolved due to being a trailing call, and we don't want that right now.
|
|
383
|
+
* assertGe(current_time(), 199)
|
|
384
|
+
* assertLe(current_time(), 400)
|
|
385
|
+
*
|
|
386
|
+
* // finally, we create a trailing call, which will take 1500ms to resolve, since less than 1000ms has passed since the last call (`b2`).
|
|
387
|
+
* await sleep(100)
|
|
388
|
+
* const c = throttled_fn(99)
|
|
389
|
+
*
|
|
390
|
+
* assertEq(await c, 100 + 99)
|
|
391
|
+
* assertGe(log_history[1][0], 300 + 1499)
|
|
392
|
+
* assertLe(log_history[1][0], 300 + 1700)
|
|
393
|
+
* assertEq(log_history[1][1], 99)
|
|
394
|
+
* assertEq(await b2, "REJECTED!")
|
|
395
|
+
* ```
|
|
396
|
+
*/
|
|
397
|
+
export declare const throttleAndTrail: <T extends unknown, ARGS extends any[], REJ>(trailing_time_ms: number, delta_time_ms: number, fn: (...args: ARGS) => T, rejection_value?: REJ) => ((...args: ARGS) => Promise<T>);
|
|
398
|
+
/** type definition of the return type of {@link syncTaskQueueFactory}.
|
|
399
|
+
*
|
|
400
|
+
* this is a synchronous task queuing function that enqueues task-functions to be executed sequentially.
|
|
401
|
+
* each task is supposed to be a function whose return value (or resolved value, if it returns a `Promise`)
|
|
402
|
+
* is wrapped in a promise and returned once the task is executed.
|
|
403
|
+
*
|
|
404
|
+
* @typeParam FN the type of the task function to be enqueued.
|
|
405
|
+
* @param task the task function to execute.
|
|
406
|
+
* @param args the arguments to be passed to the task function.
|
|
407
|
+
* @returns a promise that resolves to the return value of the task function,
|
|
408
|
+
* once all prior tasks have been executed.
|
|
409
|
+
*/
|
|
410
|
+
export type SyncTaskQueue = <FN extends ((...args: any) => any)>(task: FN, ...args: Parameters<FN>) => Promise<ReturnType<FN>>;
|
|
411
|
+
/** a factory function that generates a synchronous task queuer,
|
|
412
|
+
* which ensures that the task-functions it receives are executed sequentially,
|
|
413
|
+
* one after the other, in the order they were enqueued.
|
|
414
|
+
*
|
|
415
|
+
* TODO: consider adding this utility function to `@oazmi/kitchensink/lambda`, or the planned `@oazmi/kitchensink/duty` or `@oazmi/kitchensink/obligate`.
|
|
416
|
+
*
|
|
417
|
+
* @returns see {@link SyncTaskQueue} for the return type, and check out the example below.
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* import { assert } from "jsr:@std/assert"
|
|
422
|
+
*
|
|
423
|
+
* // some utility functions
|
|
424
|
+
* const
|
|
425
|
+
* getTime = () => (performance.now()),
|
|
426
|
+
* assertBetween = (value: number, min: number, max: number) => (assert(value >= min && value <= max)),
|
|
427
|
+
* promiseTimeout = (wait_time_ms: number): Promise<void> => {
|
|
428
|
+
* return new Promise((resolve, reject) => { setTimeout(resolve, wait_time_ms) })
|
|
429
|
+
* }
|
|
430
|
+
*
|
|
431
|
+
* const
|
|
432
|
+
* my_task_queue = syncTaskQueueFactory(),
|
|
433
|
+
* start_time = getTime()
|
|
434
|
+
*
|
|
435
|
+
* const
|
|
436
|
+
* task1 = my_task_queue(promiseTimeout, 500),
|
|
437
|
+
* task2 = my_task_queue(promiseTimeout, 500),
|
|
438
|
+
* task3 = my_task_queue(promiseTimeout, 500),
|
|
439
|
+
* task4 = my_task_queue((value: string) => (value + " world"), "hello"),
|
|
440
|
+
* task5 = my_task_queue(async (value: string) => (value + " world"), "bye bye")
|
|
441
|
+
*
|
|
442
|
+
* await task2 // will take ~1000ms to resolve.
|
|
443
|
+
* assertBetween(getTime() - start_time, 950, 1100)
|
|
444
|
+
*
|
|
445
|
+
* await task1 // will already be resolved, since `task1` preceded `task2` in the queue.
|
|
446
|
+
* assertBetween(getTime() - start_time, 950, 1100)
|
|
447
|
+
*
|
|
448
|
+
* await task3 // will take an additional ~500ms to resolve (so ~1500ms in total).
|
|
449
|
+
* assertBetween(getTime() - start_time, 1450, 1600)
|
|
450
|
+
*
|
|
451
|
+
* assert(task4 instanceof Promise)
|
|
452
|
+
* assert(await task4, "hello world") // almost instantaneous promise-resolution
|
|
453
|
+
* assertBetween(getTime() - start_time, 1450, 1600)
|
|
454
|
+
*
|
|
455
|
+
* assert(task5 instanceof Promise)
|
|
456
|
+
* assert(await task5, "bye bye world") // almost instantaneous promise-resolution
|
|
457
|
+
* assertBetween(getTime() - start_time, 1450, 1600)
|
|
458
|
+
* ```
|
|
459
|
+
*/
|
|
460
|
+
export declare const syncTaskQueueFactory: () => SyncTaskQueue;
|
|
461
|
+
/** create a queue list that can be asynchronously awaited to receive new items.
|
|
462
|
+
*
|
|
463
|
+
* TODO: should I also make the `items` non-private, so that they're accessible from super classes?
|
|
464
|
+
*
|
|
465
|
+
* @example
|
|
466
|
+
* ```ts
|
|
467
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
468
|
+
*
|
|
469
|
+
* const
|
|
470
|
+
* queue = new AwaitableQueue<string>(),
|
|
471
|
+
* promise1 = queue.shift(),
|
|
472
|
+
* promise2 = queue.shift()
|
|
473
|
+
*
|
|
474
|
+
* assertEquals(queue.getSize(), -2)
|
|
475
|
+
*
|
|
476
|
+
* queue.push("hello")
|
|
477
|
+
* assertEquals(await promise1, "hello")
|
|
478
|
+
* assertEquals(queue.getSize(), -1)
|
|
479
|
+
*
|
|
480
|
+
* queue.push("world")
|
|
481
|
+
* assertEquals(await promise2, "world")
|
|
482
|
+
* assertEquals(queue.getSize(), 0)
|
|
483
|
+
*
|
|
484
|
+
* queue.push("abcd")
|
|
485
|
+
* assertEquals(queue.getSize(), 1)
|
|
486
|
+
* // notice that when extra items are present,
|
|
487
|
+
* // an immediate value is returned rather than a promise.
|
|
488
|
+
* assertEquals(queue.shift(), "abcd")
|
|
489
|
+
*
|
|
490
|
+
* queue.push("1", "2", "3")
|
|
491
|
+
* // dump all immediately available items, clearing off the internal list.
|
|
492
|
+
* assertEquals(queue.dump(), ["1", "2", "3"])
|
|
493
|
+
* assertEquals(queue.dump(), []) // nothing else to dump.
|
|
494
|
+
*
|
|
495
|
+
* const
|
|
496
|
+
* promise3 = queue.shift(),
|
|
497
|
+
* promise4 = queue.shift(),
|
|
498
|
+
* promise5 = queue.shift(),
|
|
499
|
+
* // drop all promise resolvers, clearing off the internal list.
|
|
500
|
+
* [resolve3, resolve4, resolve5] = queue.drop()
|
|
501
|
+
*
|
|
502
|
+
* assertEquals(queue.drop(), []) // no more promise resolvers remain to be dropped.
|
|
503
|
+
* queue.push("1", "2", "3", "4", "5")
|
|
504
|
+
* assertEquals(queue.shift(), "1")
|
|
505
|
+
* assertEquals(queue.shift(), "2")
|
|
506
|
+
*
|
|
507
|
+
* // `promise3` to `promise5` remain unresolved right now.
|
|
508
|
+
* // but since we don't want forever hagging promises, we will resolve them below:
|
|
509
|
+
* resolve3(await queue.shift())
|
|
510
|
+
* resolve4(await queue.shift())
|
|
511
|
+
* resolve5(await queue.shift())
|
|
512
|
+
* assertEquals(await promise3, "3")
|
|
513
|
+
* assertEquals(await promise4, "4")
|
|
514
|
+
* assertEquals(await promise5, "5")
|
|
515
|
+
* ```
|
|
516
|
+
*/
|
|
517
|
+
export declare class AwaitableQueue<T> {
|
|
518
|
+
#private;
|
|
519
|
+
/** push items into the queue, and immediately resolve any queued up promises,
|
|
520
|
+
* otherwise just queue up the new items in the internal array.
|
|
521
|
+
*/
|
|
522
|
+
push(...items: Array<T>): number;
|
|
523
|
+
/** make a request to pop the first item in the queue.
|
|
524
|
+
* if no queued item is currently available,
|
|
525
|
+
* you will receive a promise that will resolve as soon as an item is pushed,
|
|
526
|
+
* and after all other promises that came before you have been served.
|
|
527
|
+
*/
|
|
528
|
+
shift(): MaybePromise<T>;
|
|
529
|
+
/** dump off all currently available queued items, and receive them as a returned value.
|
|
530
|
+
*
|
|
531
|
+
* > [!note]
|
|
532
|
+
* > the first item in the returned array is the first item in the queue (highest priority/first to be served),
|
|
533
|
+
* > while the last item in the array is at the end of the queue (least priority/last to be served).
|
|
534
|
+
*/
|
|
535
|
+
dump(): Array<T>;
|
|
536
|
+
/** drop off the resolvers of all currently unresolved promises in the queue.
|
|
537
|
+
* this means that all existing promises will remain hanging,
|
|
538
|
+
* unless you resolve them yourself with the returned resolver functions.
|
|
539
|
+
*
|
|
540
|
+
* > [!note]
|
|
541
|
+
* > the first item in the returned array is the first resolver function in the queue (highest priority/first to be served),
|
|
542
|
+
* > while the last item in the array is the last resolver that should be served in the queue (least priority).
|
|
543
|
+
*/
|
|
544
|
+
drop(): Array<PromiseResolver<T>>;
|
|
545
|
+
/** returns the number of immediately available items, or the number of queued up requests.
|
|
546
|
+
*
|
|
547
|
+
* - when the return value is a positive value `n`, it indicates that `|n|` number of items are queued up,
|
|
548
|
+
* and you can immediately {@link shift} `|n|` number of times.
|
|
549
|
+
* - when the return value is a negative value `n`, it indicates that `|n|` number of promises are waiting to be resolved,
|
|
550
|
+
* and that if you {@link shift} right now, you will be receiving a promise to the `|n| + 1` item in the future (relative to now).
|
|
551
|
+
*/
|
|
552
|
+
getSize(): number;
|
|
553
|
+
}
|
|
554
|
+
/** create a stack list that can be asynchronously awaited to receive new items.
|
|
555
|
+
*
|
|
556
|
+
* @example
|
|
557
|
+
* ```ts
|
|
558
|
+
* import { assertEquals } from "jsr:@std/assert"
|
|
559
|
+
*
|
|
560
|
+
* const
|
|
561
|
+
* stack = new AwaitableStack<string>(),
|
|
562
|
+
* promise1 = stack.pop(),
|
|
563
|
+
* promise2 = stack.pop()
|
|
564
|
+
*
|
|
565
|
+
* assertEquals(stack.getSize(), -2)
|
|
566
|
+
*
|
|
567
|
+
* // since this is a stack, the last promise is the first one to be served.
|
|
568
|
+
* stack.push("hello")
|
|
569
|
+
* assertEquals(await promise2, "hello")
|
|
570
|
+
* assertEquals(stack.getSize(), -1)
|
|
571
|
+
*
|
|
572
|
+
* stack.push("world")
|
|
573
|
+
* assertEquals(await promise1, "world")
|
|
574
|
+
* assertEquals(stack.getSize(), 0)
|
|
575
|
+
*
|
|
576
|
+
* stack.push("abcd")
|
|
577
|
+
* assertEquals(stack.getSize(), 1)
|
|
578
|
+
* // notice that when extra items are present,
|
|
579
|
+
* // an immediate value is returned rather than a promise.
|
|
580
|
+
* assertEquals(stack.pop(), "abcd")
|
|
581
|
+
*
|
|
582
|
+
* stack.push("1", "2", "3")
|
|
583
|
+
* // dump all immediately available items, clearing off the internal list.
|
|
584
|
+
* // the last item in the array (`"3"`) is at the top of the stack.
|
|
585
|
+
* assertEquals(stack.dump(), ["1", "2", "3"])
|
|
586
|
+
* assertEquals(stack.dump(), []) // nothing else to dump.
|
|
587
|
+
*
|
|
588
|
+
* const
|
|
589
|
+
* promise3 = stack.pop(),
|
|
590
|
+
* promise4 = stack.pop(),
|
|
591
|
+
* promise5 = stack.pop(),
|
|
592
|
+
* // drop all promise resolvers, clearing off the internal list.
|
|
593
|
+
* [resolve3, resolve4, resolve5] = stack.drop()
|
|
594
|
+
*
|
|
595
|
+
* assertEquals(stack.drop(), []) // no more promise resolvers remain to be dropped.
|
|
596
|
+
* stack.push("1", "2", "3", "4", "5")
|
|
597
|
+
* assertEquals(stack.pop(), "5")
|
|
598
|
+
* assertEquals(stack.pop(), "4")
|
|
599
|
+
*
|
|
600
|
+
* // `promise3` to `promise5` remain unresolved right now.
|
|
601
|
+
* // but since we don't want forever hagging promises, we will resolve them below:
|
|
602
|
+
* resolve5(await stack.pop())
|
|
603
|
+
* resolve4(await stack.pop())
|
|
604
|
+
* resolve3(await stack.pop())
|
|
605
|
+
* assertEquals(await promise5, "3")
|
|
606
|
+
* assertEquals(await promise4, "2")
|
|
607
|
+
* assertEquals(await promise3, "1")
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
export declare class AwaitableStack<T> {
|
|
611
|
+
#private;
|
|
612
|
+
/** push a items into the stack, and immediately resolve any lingering promises,
|
|
613
|
+
* otherwise the new items will just get stacked up in the internal items array.
|
|
614
|
+
*/
|
|
615
|
+
push(...items: Array<T>): number;
|
|
616
|
+
/** make a request to pop the top item in the stack.
|
|
617
|
+
* if no stacked item is currently available,
|
|
618
|
+
* you will receive a promise that will resolve if an item is pushed,
|
|
619
|
+
* after all other promises that came _after_ you have been served.
|
|
620
|
+
*/
|
|
621
|
+
pop(): MaybePromise<T>;
|
|
622
|
+
/** dump off all currently available stacked items, and receive them as a returned value.
|
|
623
|
+
*
|
|
624
|
+
* > [!note]
|
|
625
|
+
* > the last item in the returned array is at the top of the stack,
|
|
626
|
+
* > while the first item in the array is the bottom of the stack.
|
|
627
|
+
*/
|
|
628
|
+
dump(): Array<T>;
|
|
629
|
+
/** drop off the resolvers of all currently unresolved promises in the stack.
|
|
630
|
+
* this means that all existing promises will remain hanging,
|
|
631
|
+
* unless you resolve them yourself with the returned resolver functions.
|
|
632
|
+
*
|
|
633
|
+
* > [!note]
|
|
634
|
+
* > the last item in the returned array is at the top of the stack, meaning that it should be served/resolved first,
|
|
635
|
+
* > while the first item in the array is the last resolver that should be served (bottom of the stack).
|
|
636
|
+
*/
|
|
637
|
+
drop(): Array<PromiseResolver<T>>;
|
|
638
|
+
/** returns the number of immediately available items, or the number of queued up requests.
|
|
639
|
+
*
|
|
640
|
+
* - when the return value is a positive value `n`, it indicates that `|n|` number of items are queued up,
|
|
641
|
+
* and you can immediately {@link shift} `|n|` number of times.
|
|
642
|
+
* - when the return value is a negative value `n`, it indicates that `|n|` number of promises are waiting to be resolved,
|
|
643
|
+
* and that if you {@link shift} right now, you will be receiving a promise to the `|n| + 1` item in the future (relative to now).
|
|
644
|
+
*/
|
|
645
|
+
getSize(): number;
|
|
646
|
+
}
|
|
647
|
+
//# sourceMappingURL=promiseman.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"promiseman.d.ts","sourceRoot":"","sources":["../../../../../../../src/deps/jsr.io/@oazmi/kitchensink/0.10.0/src/promiseman.ts"],"names":[],"mappings":"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"}
|