@ezez/utils 1.0.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/.prettierignore +3 -0
- package/.prettierrc.json +1 -0
- package/CHANGELOG.md +244 -0
- package/LICENSE +21 -0
- package/README.md +79 -0
- package/babel.config.cjs +6 -0
- package/dist/cap.d.ts +3 -0
- package/dist/cap.d.ts.map +1 -0
- package/dist/cap.js +14 -0
- package/dist/cap.js.map +1 -0
- package/dist/capitalize.d.ts +3 -0
- package/dist/capitalize.d.ts.map +1 -0
- package/dist/capitalize.js +9 -0
- package/dist/capitalize.js.map +1 -0
- package/dist/coalesce.d.ts +3 -0
- package/dist/coalesce.d.ts.map +1 -0
- package/dist/coalesce.js +14 -0
- package/dist/coalesce.js.map +1 -0
- package/dist/ensureArray.d.ts +3 -0
- package/dist/ensureArray.d.ts.map +1 -0
- package/dist/ensureArray.js +11 -0
- package/dist/ensureArray.js.map +1 -0
- package/dist/ensureError.d.ts +3 -0
- package/dist/ensureError.d.ts.map +1 -0
- package/dist/ensureError.js +11 -0
- package/dist/ensureError.js.map +1 -0
- package/dist/get.d.ts +7 -0
- package/dist/get.d.ts.map +1 -0
- package/dist/get.js +19 -0
- package/dist/get.js.map +1 -0
- package/dist/getMultiple.d.ts +7 -0
- package/dist/getMultiple.d.ts.map +1 -0
- package/dist/getMultiple.js +18 -0
- package/dist/getMultiple.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -0
- package/dist/insertSeparator.d.ts +3 -0
- package/dist/insertSeparator.d.ts.map +1 -0
- package/dist/insertSeparator.js +18 -0
- package/dist/insertSeparator.js.map +1 -0
- package/dist/isEmpty.d.ts +3 -0
- package/dist/isEmpty.d.ts.map +1 -0
- package/dist/isEmpty.js +26 -0
- package/dist/isEmpty.js.map +1 -0
- package/dist/isPlainObject.d.ts +3 -0
- package/dist/isPlainObject.d.ts.map +1 -0
- package/dist/isPlainObject.js +10 -0
- package/dist/isPlainObject.js.map +1 -0
- package/dist/last.d.ts +3 -0
- package/dist/last.d.ts.map +1 -0
- package/dist/last.js +6 -0
- package/dist/last.js.map +1 -0
- package/dist/mapAsync.d.ts +3 -0
- package/dist/mapAsync.d.ts.map +1 -0
- package/dist/mapAsync.js +22 -0
- package/dist/mapAsync.js.map +1 -0
- package/dist/mapValues.d.ts +6 -0
- package/dist/mapValues.d.ts.map +1 -0
- package/dist/mapValues.js +18 -0
- package/dist/mapValues.js.map +1 -0
- package/dist/match.d.ts +8 -0
- package/dist/match.d.ts.map +1 -0
- package/dist/match.js +20 -0
- package/dist/match.js.map +1 -0
- package/dist/merge.d.ts +15 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +28 -0
- package/dist/merge.js.map +1 -0
- package/dist/mostFrequent.d.ts +3 -0
- package/dist/mostFrequent.d.ts.map +1 -0
- package/dist/mostFrequent.js +21 -0
- package/dist/mostFrequent.js.map +1 -0
- package/dist/noop.d.ts +3 -0
- package/dist/noop.d.ts.map +1 -0
- package/dist/noop.js +6 -0
- package/dist/noop.js.map +1 -0
- package/dist/omit.d.ts +5 -0
- package/dist/omit.d.ts.map +1 -0
- package/dist/omit.js +21 -0
- package/dist/omit.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/pick.d.ts +5 -0
- package/dist/pick.d.ts.map +1 -0
- package/dist/pick.js +20 -0
- package/dist/pick.js.map +1 -0
- package/dist/pull.d.ts +3 -0
- package/dist/pull.d.ts.map +1 -0
- package/dist/pull.js +14 -0
- package/dist/pull.js.map +1 -0
- package/dist/remove.d.ts +3 -0
- package/dist/remove.d.ts.map +1 -0
- package/dist/remove.js +18 -0
- package/dist/remove.js.map +1 -0
- package/dist/rethrow.d.ts +3 -0
- package/dist/rethrow.d.ts.map +1 -0
- package/dist/rethrow.js +8 -0
- package/dist/rethrow.js.map +1 -0
- package/dist/scale.d.ts +3 -0
- package/dist/scale.d.ts.map +1 -0
- package/dist/scale.js +8 -0
- package/dist/scale.js.map +1 -0
- package/dist/seq.d.ts +8 -0
- package/dist/seq.d.ts.map +1 -0
- package/dist/seq.js +45 -0
- package/dist/seq.js.map +1 -0
- package/dist/set.d.ts +7 -0
- package/dist/set.d.ts.map +1 -0
- package/dist/set.js +25 -0
- package/dist/set.js.map +1 -0
- package/dist/setImmutable.d.ts +8 -0
- package/dist/setImmutable.d.ts.map +1 -0
- package/dist/setImmutable.js +59 -0
- package/dist/setImmutable.js.map +1 -0
- package/dist/sortBy.d.ts +3 -0
- package/dist/sortBy.d.ts.map +1 -0
- package/dist/sortBy.js +15 -0
- package/dist/sortBy.js.map +1 -0
- package/dist/throttle.d.ts +13 -0
- package/dist/throttle.d.ts.map +1 -0
- package/dist/throttle.js +82 -0
- package/dist/throttle.js.map +1 -0
- package/dist/truthy.d.ts +3 -0
- package/dist/truthy.d.ts.map +1 -0
- package/dist/truthy.js +8 -0
- package/dist/truthy.js.map +1 -0
- package/dist/wait.d.ts +3 -0
- package/dist/wait.d.ts.map +1 -0
- package/dist/wait.js +10 -0
- package/dist/wait.js.map +1 -0
- package/dist/waitFor.d.ts +3 -0
- package/dist/waitFor.d.ts.map +1 -0
- package/dist/waitFor.js +34 -0
- package/dist/waitFor.js.map +1 -0
- package/dist/waitSync.d.ts +3 -0
- package/dist/waitSync.d.ts.map +1 -0
- package/dist/waitSync.js +9 -0
- package/dist/waitSync.js.map +1 -0
- package/docs/.nojekyll +1 -0
- package/docs/assets/highlight.css +78 -0
- package/docs/assets/main.js +58 -0
- package/docs/assets/pages.css +14 -0
- package/docs/assets/search.js +1 -0
- package/docs/assets/style.css +1280 -0
- package/docs/functions/cap.html +116 -0
- package/docs/functions/capitalize.html +121 -0
- package/docs/functions/coalesce.html +127 -0
- package/docs/functions/ensureArray.html +114 -0
- package/docs/functions/ensureError.html +110 -0
- package/docs/functions/get.html +138 -0
- package/docs/functions/getMultiple.html +129 -0
- package/docs/functions/insertSeparator.html +123 -0
- package/docs/functions/isEmpty.html +139 -0
- package/docs/functions/isPlainObject.html +108 -0
- package/docs/functions/last.html +126 -0
- package/docs/functions/mapAsync.html +144 -0
- package/docs/functions/mapValues.html +130 -0
- package/docs/functions/match.html +122 -0
- package/docs/functions/merge.html +464 -0
- package/docs/functions/mostFrequent.html +111 -0
- package/docs/functions/noop.html +101 -0
- package/docs/functions/omit.html +129 -0
- package/docs/functions/pick.html +129 -0
- package/docs/functions/pull.html +113 -0
- package/docs/functions/remove.html +129 -0
- package/docs/functions/rethrow.html +106 -0
- package/docs/functions/scale.html +117 -0
- package/docs/functions/seq.html +128 -0
- package/docs/functions/seqEarlyBreak.html +126 -0
- package/docs/functions/set.html +138 -0
- package/docs/functions/setImmutable.html +137 -0
- package/docs/functions/sortBy.html +135 -0
- package/docs/functions/throttle.html +131 -0
- package/docs/functions/truthy.html +118 -0
- package/docs/functions/wait.html +109 -0
- package/docs/functions/waitFor.html +130 -0
- package/docs/functions/waitSync.html +109 -0
- package/docs/index.html +182 -0
- package/docs/interfaces/GetMultipleSource.html +106 -0
- package/docs/interfaces/GetSource.html +106 -0
- package/docs/interfaces/SetImmutableSource.html +106 -0
- package/docs/interfaces/SetSource.html +106 -0
- package/docs/interfaces/ThrottleOptions.html +80 -0
- package/docs/interfaces/ThrottledFunctionExtras.html +96 -0
- package/docs/modules.html +152 -0
- package/docs/pages/Introduction.html +94 -0
- package/docs/types/MapValuesFn.html +134 -0
- package/docs/types/MatchCallback.html +113 -0
- package/docs/types/SeqEarlyBreaker.html +114 -0
- package/docs/types/SeqFn.html +112 -0
- package/docs/types/SeqFunctions.html +105 -0
- package/docs/types/SetImmutablePath.html +99 -0
- package/docs/types/ThrottledFunction.html +113 -0
- package/docs/variables/mapValuesUNSET.html +101 -0
- package/docs/variables/mergeUNSET.html +103 -0
- package/esm/cap.d.ts +3 -0
- package/esm/cap.d.ts.map +1 -0
- package/esm/cap.js +11 -0
- package/esm/cap.js.map +1 -0
- package/esm/capitalize.d.ts +3 -0
- package/esm/capitalize.d.ts.map +1 -0
- package/esm/capitalize.js +6 -0
- package/esm/capitalize.js.map +1 -0
- package/esm/coalesce.d.ts +3 -0
- package/esm/coalesce.d.ts.map +1 -0
- package/esm/coalesce.js +11 -0
- package/esm/coalesce.js.map +1 -0
- package/esm/ensureArray.d.ts +3 -0
- package/esm/ensureArray.d.ts.map +1 -0
- package/esm/ensureArray.js +8 -0
- package/esm/ensureArray.js.map +1 -0
- package/esm/ensureError.d.ts +3 -0
- package/esm/ensureError.d.ts.map +1 -0
- package/esm/ensureError.js +8 -0
- package/esm/ensureError.js.map +1 -0
- package/esm/get.d.ts +7 -0
- package/esm/get.d.ts.map +1 -0
- package/esm/get.js +16 -0
- package/esm/get.js.map +1 -0
- package/esm/getMultiple.d.ts +7 -0
- package/esm/getMultiple.d.ts.map +1 -0
- package/esm/getMultiple.js +15 -0
- package/esm/getMultiple.js.map +1 -0
- package/esm/index.d.ts +33 -0
- package/esm/index.d.ts.map +1 -0
- package/esm/index.js +33 -0
- package/esm/index.js.map +1 -0
- package/esm/insertSeparator.d.ts +3 -0
- package/esm/insertSeparator.d.ts.map +1 -0
- package/esm/insertSeparator.js +15 -0
- package/esm/insertSeparator.js.map +1 -0
- package/esm/isEmpty.d.ts +3 -0
- package/esm/isEmpty.d.ts.map +1 -0
- package/esm/isEmpty.js +23 -0
- package/esm/isEmpty.js.map +1 -0
- package/esm/isPlainObject.d.ts +3 -0
- package/esm/isPlainObject.d.ts.map +1 -0
- package/esm/isPlainObject.js +7 -0
- package/esm/isPlainObject.js.map +1 -0
- package/esm/last.d.ts +3 -0
- package/esm/last.d.ts.map +1 -0
- package/esm/last.js +3 -0
- package/esm/last.js.map +1 -0
- package/esm/mapAsync.d.ts +3 -0
- package/esm/mapAsync.d.ts.map +1 -0
- package/esm/mapAsync.js +19 -0
- package/esm/mapAsync.js.map +1 -0
- package/esm/mapValues.d.ts +6 -0
- package/esm/mapValues.d.ts.map +1 -0
- package/esm/mapValues.js +14 -0
- package/esm/mapValues.js.map +1 -0
- package/esm/match.d.ts +8 -0
- package/esm/match.d.ts.map +1 -0
- package/esm/match.js +17 -0
- package/esm/match.js.map +1 -0
- package/esm/merge.d.ts +15 -0
- package/esm/merge.d.ts.map +1 -0
- package/esm/merge.js +24 -0
- package/esm/merge.js.map +1 -0
- package/esm/mostFrequent.d.ts +3 -0
- package/esm/mostFrequent.d.ts.map +1 -0
- package/esm/mostFrequent.js +18 -0
- package/esm/mostFrequent.js.map +1 -0
- package/esm/noop.d.ts +3 -0
- package/esm/noop.d.ts.map +1 -0
- package/esm/noop.js +3 -0
- package/esm/noop.js.map +1 -0
- package/esm/omit.d.ts +5 -0
- package/esm/omit.d.ts.map +1 -0
- package/esm/omit.js +20 -0
- package/esm/omit.js.map +1 -0
- package/esm/pick.d.ts +5 -0
- package/esm/pick.d.ts.map +1 -0
- package/esm/pick.js +17 -0
- package/esm/pick.js.map +1 -0
- package/esm/pull.d.ts +3 -0
- package/esm/pull.d.ts.map +1 -0
- package/esm/pull.js +11 -0
- package/esm/pull.js.map +1 -0
- package/esm/remove.d.ts +3 -0
- package/esm/remove.d.ts.map +1 -0
- package/esm/remove.js +15 -0
- package/esm/remove.js.map +1 -0
- package/esm/rethrow.d.ts +3 -0
- package/esm/rethrow.d.ts.map +1 -0
- package/esm/rethrow.js +5 -0
- package/esm/rethrow.js.map +1 -0
- package/esm/scale.d.ts +3 -0
- package/esm/scale.d.ts.map +1 -0
- package/esm/scale.js +5 -0
- package/esm/scale.js.map +1 -0
- package/esm/seq.d.ts +8 -0
- package/esm/seq.d.ts.map +1 -0
- package/esm/seq.js +41 -0
- package/esm/seq.js.map +1 -0
- package/esm/set.d.ts +7 -0
- package/esm/set.d.ts.map +1 -0
- package/esm/set.js +22 -0
- package/esm/set.js.map +1 -0
- package/esm/setImmutable.d.ts +8 -0
- package/esm/setImmutable.d.ts.map +1 -0
- package/esm/setImmutable.js +56 -0
- package/esm/setImmutable.js.map +1 -0
- package/esm/sortBy.d.ts +3 -0
- package/esm/sortBy.d.ts.map +1 -0
- package/esm/sortBy.js +12 -0
- package/esm/sortBy.js.map +1 -0
- package/esm/throttle.d.ts +13 -0
- package/esm/throttle.d.ts.map +1 -0
- package/esm/throttle.js +79 -0
- package/esm/throttle.js.map +1 -0
- package/esm/truthy.d.ts +3 -0
- package/esm/truthy.d.ts.map +1 -0
- package/esm/truthy.js +5 -0
- package/esm/truthy.js.map +1 -0
- package/esm/wait.d.ts +3 -0
- package/esm/wait.d.ts.map +1 -0
- package/esm/wait.js +7 -0
- package/esm/wait.js.map +1 -0
- package/esm/waitFor.d.ts +3 -0
- package/esm/waitFor.d.ts.map +1 -0
- package/esm/waitFor.js +31 -0
- package/esm/waitFor.js.map +1 -0
- package/esm/waitSync.d.ts +3 -0
- package/esm/waitSync.d.ts.map +1 -0
- package/esm/waitSync.js +6 -0
- package/esm/waitSync.js.map +1 -0
- package/package.json +75 -0
- package/src/cap.spec.ts +36 -0
- package/src/cap.ts +19 -0
- package/src/capitalize.spec.ts +18 -0
- package/src/capitalize.ts +16 -0
- package/src/coalesce.spec.ts +23 -0
- package/src/coalesce.ts +21 -0
- package/src/ensureArray.spec.ts +87 -0
- package/src/ensureArray.ts +13 -0
- package/src/ensureError.spec.ts +29 -0
- package/src/ensureError.ts +15 -0
- package/src/get.spec.ts +183 -0
- package/src/get.ts +53 -0
- package/src/getMultiple.spec.ts +25 -0
- package/src/getMultiple.ts +47 -0
- package/src/index.ts +33 -0
- package/src/insertSeparator.spec.ts +29 -0
- package/src/insertSeparator.ts +22 -0
- package/src/isEmpty.spec.ts +130 -0
- package/src/isEmpty.ts +50 -0
- package/src/isPlainObject.spec.ts +42 -0
- package/src/isPlainObject.ts +18 -0
- package/src/last.spec.ts +88 -0
- package/src/last.ts +12 -0
- package/src/mapAsync.spec.ts +39 -0
- package/src/mapAsync.ts +41 -0
- package/src/mapValues.spec.ts +178 -0
- package/src/mapValues.ts +57 -0
- package/src/match.spec.ts +11 -0
- package/src/match.ts +30 -0
- package/src/merge.spec.ts +69 -0
- package/src/merge.ts +58 -0
- package/src/mostFrequent.spec.ts +35 -0
- package/src/mostFrequent.ts +27 -0
- package/src/noop.ts +8 -0
- package/src/omit.spec.ts +181 -0
- package/src/omit.ts +43 -0
- package/src/pick.spec.ts +168 -0
- package/src/pick.ts +39 -0
- package/src/pull.spec.ts +54 -0
- package/src/pull.ts +18 -0
- package/src/remove.spec.ts +63 -0
- package/src/remove.ts +26 -0
- package/src/rethrow.ts +12 -0
- package/src/scale.ts +18 -0
- package/src/seq.spec.ts +157 -0
- package/src/seq.ts +104 -0
- package/src/set.spec.ts +348 -0
- package/src/set.ts +59 -0
- package/src/setImmutable.spec.ts +241 -0
- package/src/setImmutable.ts +104 -0
- package/src/sortBy.spec.ts +56 -0
- package/src/sortBy.ts +24 -0
- package/src/throttle.spec.ts +136 -0
- package/src/throttle.ts +153 -0
- package/src/truthy.spec.ts +21 -0
- package/src/truthy.ts +13 -0
- package/src/wait.spec.ts +21 -0
- package/src/wait.ts +14 -0
- package/src/waitFor.ts +47 -0
- package/src/waitSync.spec.ts +21 -0
- package/src/waitSync.ts +14 -0
- package/tutorials/Introduction.md +1 -0
package/src/throttle.ts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
interface Opts {
|
|
2
|
+
/**
|
|
3
|
+
* Should function be invoked immediately on first call to throttled function
|
|
4
|
+
*/
|
|
5
|
+
leading?: boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Should function be called after given time
|
|
8
|
+
*/
|
|
9
|
+
trailing?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface Extras {
|
|
13
|
+
/**
|
|
14
|
+
* Stops any planned calls (and resets the `time` array progress)
|
|
15
|
+
*/
|
|
16
|
+
cancel: () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Immediately runs planned call.
|
|
19
|
+
*/
|
|
20
|
+
flush: () => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const defaultOptions: Required<Opts> = {
|
|
24
|
+
leading: true,
|
|
25
|
+
trailing: true,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
29
|
+
type CanReturnUndefined<F extends (...args: any[]) => any> = (...args: Parameters<F>) => ReturnType<F> | undefined;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Creates a throttled function that calls given function only once every given time. Throttled function takes the same
|
|
33
|
+
* arguments, returns "cached" value of last "real" call to the given function.
|
|
34
|
+
* Time (in ms) can be specified as an array - each "real" call to the function will then pick next value of that array
|
|
35
|
+
* as a time to wait for the next "real" call. This is useful for throttled notifications or auto-retries. Last value of
|
|
36
|
+
* the array will be used if no more values.
|
|
37
|
+
* Returned function also includes `cancel` property - call it to stop any planned calls (and reset the `time` array
|
|
38
|
+
* progress) and `flush` property - call it to immediately run planned call.
|
|
39
|
+
*
|
|
40
|
+
* You can provide options to specify if function should be invoked immediately on first call to throttled function
|
|
41
|
+
* (`leading` property) and if it should be called after given time (`trailing` property).
|
|
42
|
+
*
|
|
43
|
+
* If (this is default) both `leading` and `trailing` property are true then it's required to call throttled function at
|
|
44
|
+
* least twice.
|
|
45
|
+
* @param {function} fn - function to throttle
|
|
46
|
+
* @param {number | number[]} time - throttle time as number or array of numbers (min 1 element)
|
|
47
|
+
* @param {Opts} options
|
|
48
|
+
*/
|
|
49
|
+
const throttle = <RT, F extends (...args: any[]) => RT>( // eslint-disable-line max-lines-per-function, @typescript-eslint/no-explicit-any, max-len
|
|
50
|
+
fn: F, time: number | [number, ...number[]] = 0, options?: Opts,
|
|
51
|
+
): CanReturnUndefined<F> & Extras => {
|
|
52
|
+
const opts: Required<Opts> = {
|
|
53
|
+
leading: options?.leading ?? defaultOptions.leading,
|
|
54
|
+
trailing: options?.trailing ?? defaultOptions.trailing,
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
if (!opts.trailing && !opts.leading) {
|
|
58
|
+
throw new TypeError("Throttle with trailing & leading options `false` won't do anything.");
|
|
59
|
+
}
|
|
60
|
+
if (typeof time !== "number" && !time.length) {
|
|
61
|
+
throw new TypeError("`time` must be an array with at least one number.");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const finalTime = typeof time === "number" ? time : time[time.length - 1];
|
|
65
|
+
|
|
66
|
+
let lastRun = 0,
|
|
67
|
+
timeoutId: ReturnType<typeof setTimeout> | null = null,
|
|
68
|
+
lastResult: RT | undefined,
|
|
69
|
+
lastArgs: Parameters<F>,
|
|
70
|
+
lastTime = typeof time === "number" ? time : time[0],
|
|
71
|
+
leadingCalled = false;
|
|
72
|
+
|
|
73
|
+
const times = typeof time === "number" ? [time] : [...time];
|
|
74
|
+
|
|
75
|
+
// eslint-disable-next-line max-statements
|
|
76
|
+
const throttledFn = ((...args: Parameters<F>) => {
|
|
77
|
+
lastArgs = args;
|
|
78
|
+
if (timeoutId !== null) { // if timer goes on, then we shouldn't do anything
|
|
79
|
+
return lastResult;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!opts.trailing) { // we don't want a timer
|
|
83
|
+
if (Date.now() - lastRun < lastTime) { // it's not yet the time to call the func
|
|
84
|
+
return lastResult;
|
|
85
|
+
}
|
|
86
|
+
lastTime = times.shift() ?? finalTime;
|
|
87
|
+
lastRun = Date.now();
|
|
88
|
+
lastResult = fn(...args);
|
|
89
|
+
return lastResult;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// we want timers here!
|
|
93
|
+
const diffLastRun = Date.now() - lastRun;
|
|
94
|
+
if (opts.leading && (!leadingCalled || typeof time === "number") && diffLastRun >= (times[0] ?? finalTime)) {
|
|
95
|
+
// we want initial run and last run was long time ago
|
|
96
|
+
lastRun = Date.now();
|
|
97
|
+
lastResult = fn(...args);
|
|
98
|
+
leadingCalled = true;
|
|
99
|
+
return lastResult;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (lastRun || !opts.leading) {
|
|
103
|
+
lastTime = times.shift() ?? finalTime;
|
|
104
|
+
}
|
|
105
|
+
timeoutId = setTimeout(() => {
|
|
106
|
+
timeoutId = null;
|
|
107
|
+
lastRun = Date.now();
|
|
108
|
+
lastResult = fn(...args);
|
|
109
|
+
}, lastRun ? (lastTime - diffLastRun + 1) : lastTime);
|
|
110
|
+
|
|
111
|
+
return lastResult;
|
|
112
|
+
}) as (CanReturnUndefined<F> & Extras);
|
|
113
|
+
|
|
114
|
+
throttledFn.cancel = () => {
|
|
115
|
+
timeoutId !== null && clearTimeout(timeoutId);
|
|
116
|
+
timeoutId = null;
|
|
117
|
+
lastRun = 0;
|
|
118
|
+
lastResult = undefined;
|
|
119
|
+
|
|
120
|
+
// we can't replace `times` with different instance - throttledFn already has one, so we clear the array
|
|
121
|
+
// and refill it
|
|
122
|
+
times.length = 0;
|
|
123
|
+
if (typeof time === "number") {
|
|
124
|
+
times.push(time);
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
times.push(...time);
|
|
128
|
+
}
|
|
129
|
+
lastTime = typeof time === "number" ? time : time[0];
|
|
130
|
+
};
|
|
131
|
+
throttledFn.flush = () => {
|
|
132
|
+
if (timeoutId !== null) {
|
|
133
|
+
lastRun = Date.now();
|
|
134
|
+
lastResult = fn(...lastArgs);
|
|
135
|
+
clearTimeout(timeoutId);
|
|
136
|
+
timeoutId = null;
|
|
137
|
+
return throttledFn(...lastArgs);
|
|
138
|
+
}
|
|
139
|
+
return lastResult;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return throttledFn;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
export {
|
|
146
|
+
throttle,
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
export type {
|
|
150
|
+
Extras as ThrottledFunctionExtras,
|
|
151
|
+
Opts as ThrottleOptions,
|
|
152
|
+
CanReturnUndefined as ThrottledFunction,
|
|
153
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { truthy } from "./truthy.js";
|
|
2
|
+
|
|
3
|
+
describe("truthy", function() {
|
|
4
|
+
it("returns true on truthy values", function() {
|
|
5
|
+
truthy(true).must.be.true();
|
|
6
|
+
truthy(() => {}).must.be.true();
|
|
7
|
+
truthy(1).must.be.true();
|
|
8
|
+
truthy("a").must.be.true();
|
|
9
|
+
truthy([]).must.be.true();
|
|
10
|
+
truthy({}).must.be.true();
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it("returns false on falsy values", function() {
|
|
14
|
+
truthy(false).must.be.false();
|
|
15
|
+
truthy(null).must.be.false();
|
|
16
|
+
truthy(0).must.be.false();
|
|
17
|
+
truthy("").must.be.false();
|
|
18
|
+
truthy(NaN).must.be.false();
|
|
19
|
+
truthy(undefined).must.be.false();
|
|
20
|
+
});
|
|
21
|
+
});
|
package/src/truthy.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true if value is truthy, useful with `Array.prototype.filter` and TypeScript (`[].filter(Boolean)` won't
|
|
3
|
+
* filter out falsy values from the types)
|
|
4
|
+
* @param {*} val - test value
|
|
5
|
+
* @returns {boolean} - is value truthy
|
|
6
|
+
*/
|
|
7
|
+
const truthy = <T>(val: T | null | undefined | "" | false | 0): val is T => {
|
|
8
|
+
return Boolean(val);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
truthy,
|
|
13
|
+
};
|
package/src/wait.spec.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { wait } from "./wait.js";
|
|
2
|
+
|
|
3
|
+
describe("wait", () => {
|
|
4
|
+
it("returns a promise", () => {
|
|
5
|
+
wait(0).must.be.instanceof(Promise);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("waits given time", async () => {
|
|
9
|
+
const start1 = Date.now();
|
|
10
|
+
await wait(5);
|
|
11
|
+
const end1 = Date.now();
|
|
12
|
+
(end1 - start1).must.be.gte(5);
|
|
13
|
+
|
|
14
|
+
const start2 = Date.now();
|
|
15
|
+
await wait(100);
|
|
16
|
+
const end2 = Date.now();
|
|
17
|
+
(end2 - start2).must.be.gte(100);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// @TODO does not block test
|
|
21
|
+
});
|
package/src/wait.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a promise that resolves after given time
|
|
3
|
+
* @param {number} timeMs - time to wait
|
|
4
|
+
* @returns {Promise<void>}
|
|
5
|
+
*/
|
|
6
|
+
const wait = (timeMs = 0) => {
|
|
7
|
+
return new Promise<void>((resolve) => {
|
|
8
|
+
setTimeout(() => { resolve(); }, timeMs);
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
wait,
|
|
14
|
+
};
|
package/src/waitFor.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const DEFAULT_INTERVAL = 50;
|
|
2
|
+
|
|
3
|
+
type TTimeout = ReturnType<typeof setTimeout>;
|
|
4
|
+
type TInterval = ReturnType<typeof setInterval>;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Runs the callback function every specified interval and returns a Promise that resolves when the callback returns
|
|
8
|
+
* truthy value.
|
|
9
|
+
* Pro-tip: Value returned from the callback is returned via resolved Promise. If you want to pass back falsy value then
|
|
10
|
+
* wrap your potential return value with an object or array.
|
|
11
|
+
* @param {function} fn - callback function
|
|
12
|
+
* @param {number} interval - interval between checks
|
|
13
|
+
* @param {number} timeout - optional timeout
|
|
14
|
+
*/
|
|
15
|
+
const waitFor = <T>(fn: () => T, interval = DEFAULT_INTERVAL, timeout = Infinity) => {
|
|
16
|
+
return new Promise<T>((resolve, reject) => {
|
|
17
|
+
let intervalTimer: TInterval, failTimer: TTimeout;
|
|
18
|
+
|
|
19
|
+
if (isFinite(timeout)) {
|
|
20
|
+
failTimer = setTimeout(() => {
|
|
21
|
+
reject(new Error("[waitFor] Timeout"));
|
|
22
|
+
clearInterval(intervalTimer);
|
|
23
|
+
}, timeout);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
intervalTimer = setInterval(() => {
|
|
27
|
+
try {
|
|
28
|
+
const result = fn();
|
|
29
|
+
if (result) {
|
|
30
|
+
clearTimeout(failTimer);
|
|
31
|
+
clearInterval(intervalTimer);
|
|
32
|
+
resolve(result);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error: unknown) {
|
|
36
|
+
clearTimeout(failTimer);
|
|
37
|
+
clearInterval(intervalTimer);
|
|
38
|
+
|
|
39
|
+
const e: Error & { details?: unknown } = new Error("[waitFor] check function threw an error");
|
|
40
|
+
e.details = { error };
|
|
41
|
+
reject(e);
|
|
42
|
+
}
|
|
43
|
+
}, interval);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { waitFor };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { waitSync } from "./waitSync.js";
|
|
2
|
+
|
|
3
|
+
describe("wait", () => {
|
|
4
|
+
it("doesn't return value", () => {
|
|
5
|
+
must(waitSync(0)).be.equal(undefined); // eslint-disable-line @typescript-eslint/no-confusing-void-expression
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
it("waits given time", () => {
|
|
9
|
+
const start1 = Date.now();
|
|
10
|
+
waitSync(5);
|
|
11
|
+
const end1 = Date.now();
|
|
12
|
+
(end1 - start1).must.be.gte(5);
|
|
13
|
+
|
|
14
|
+
const start2 = Date.now();
|
|
15
|
+
waitSync(100);
|
|
16
|
+
const end2 = Date.now();
|
|
17
|
+
(end2 - start2).must.be.gte(100);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
// @TODO test that nothing else could happen during wait
|
|
21
|
+
});
|
package/src/waitSync.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synchronously wait for a given time, blocking the event loop [!]
|
|
3
|
+
* @param {number} timeMs - time to wait
|
|
4
|
+
* @returns {Promise<void>}
|
|
5
|
+
*/
|
|
6
|
+
const waitSync = (timeMs = 0) => {
|
|
7
|
+
const s = Date.now();
|
|
8
|
+
// eslint-disable-next-line no-empty
|
|
9
|
+
while (Date.now() - s < timeMs) {}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
waitSync,
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
WIP.
|