vivth 0.9.4 → 0.11.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/README.md +21 -46
- package/dev/index.mjs +2 -0
- package/index.mjs +8 -8
- package/package.json +1 -1
- package/src/class/$.mjs +39 -29
- package/src/class/Derived.mjs +27 -11
- package/src/class/PingFIFO.mjs +78 -0
- package/src/class/PingUnique.mjs +84 -0
- package/src/class/Q.mjs +22 -12
- package/src/class/Signal.mjs +31 -23
- package/src/function/NewQBlock.mjs +39 -0
- package/src/function/{tryAsync.export.mjs → TryAsync.mjs} +1 -1
- package/src/function/{trySync.export.mjs → TrySync.mjs} +1 -1
- package/src/types/{anyButUndefined.type.mjs → AnyButUndefined.type.mjs} +1 -1
- package/tsconfig.json +1 -1
- package/types/index.d.mts +6 -8
- package/types/src/class/$.d.mts +26 -13
- package/types/src/class/Derived.d.mts +18 -4
- package/types/src/class/PingFIFO.d.mts +57 -0
- package/types/src/class/PingUnique.d.mts +48 -0
- package/types/src/class/Q.d.mts +12 -5
- package/types/src/class/Signal.d.mts +15 -14
- package/types/src/function/NewQBlock.d.mts +1 -0
- package/types/src/function/{tryAsync.export.d.mts → TryAsync.d.mts} +1 -1
- package/types/src/function/TrySync.d.mts +1 -0
- package/types/src/types/AnyButUndefined.type.d.mts +1 -0
- package/src/function/New$.mjs +0 -28
- package/src/function/NewDerived.mjs +0 -28
- package/src/function/NewPingFIFO.mjs +0 -91
- package/src/function/NewPingUnique.mjs +0 -92
- package/src/function/NewSignal.mjs +0 -28
- package/types/src/function/New$.d.mts +0 -2
- package/types/src/function/NewDerived.d.mts +0 -2
- package/types/src/function/NewPingFIFO.d.mts +0 -1
- package/types/src/function/NewPingUnique.d.mts +0 -1
- package/types/src/function/NewSignal.d.mts +0 -2
- package/types/src/function/trySync.export.d.mts +0 -1
- package/types/src/types/anyButUndefined.type.d.mts +0 -1
package/README.md
CHANGED
|
@@ -14,79 +14,67 @@ bun i vivth
|
|
|
14
14
|
- `vivth` technically can run in any `js runtime`, since it uses non platform specific api;
|
|
15
15
|
- it is written specifically to be used as a primitives for javascript library or runtime, so there are no complex abstraction is, nor will be, added in `vivth` it self;
|
|
16
16
|
|
|
17
|
+
### version
|
|
18
|
+
- 0.11.x: drop function wrapper for all classes, for better runtime performance
|
|
17
19
|
## exported-api-and-type-list
|
|
18
20
|
- [$](#$)
|
|
19
21
|
- [Derived](#derived)
|
|
22
|
+
- [PingFIFO](#pingfifo)
|
|
23
|
+
- [PingUnique](#pingunique)
|
|
20
24
|
- [Q](#q)
|
|
21
25
|
- [Signal](#signal)
|
|
22
|
-
- [
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [NewPingUnique](#newpingunique)
|
|
26
|
-
- [NewSignal](#newsignal)
|
|
27
|
-
- [tryAsync](#tryasync)
|
|
28
|
-
- [trySync](#trysync)
|
|
26
|
+
- [NewQBlock](#newqblock)
|
|
27
|
+
- [TryAsync](#tryasync)
|
|
28
|
+
- [TrySync](#trysync)
|
|
29
29
|
<h2 id="$">$</h2>
|
|
30
30
|
|
|
31
|
-
- a class to `autosubscribe` to an signal changes (`Derived` and `Signal` alike);
|
|
32
|
-
for minimal total bundle size use `function` [New$](#new$) instead;
|
|
31
|
+
- a class to `autosubscribe` to an signal changes (`Derived` and `Signal` alike);
|
|
33
32
|
// runs everytime signal.value changes;
|
|
34
33
|
return signal.value * 2;
|
|
35
34
|
// runs everytime signal.value changes;
|
|
36
35
|
console.log(signal.value);
|
|
37
36
|
// console.log(derived.value);
|
|
38
37
|
|
|
39
38
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
40
39
|
|
|
41
40
|
<h2 id="derived">Derived</h2>
|
|
42
41
|
|
|
43
|
-
- a class for creating signal which its value are derived from other signal (`Derived` and `Signal` alike);
|
|
44
|
-
can be subscribed by using [New$](#new$);
|
|
45
|
-
for minimal total bundle size use `function` [NewDerived](#newderived) instead;
|
|
42
|
+
- a class for creating signal which its value are derived from other signal (`Derived` and `Signal` alike);
|
|
46
43
|
// runs everytime signal.value changes;
|
|
47
44
|
return signal.value * 2;
|
|
48
45
|
// runs everytime derived.value changes;
|
|
49
46
|
console.log(derived.value);
|
|
50
47
|
|
|
51
48
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
52
49
|
|
|
53
|
-
<h2 id="
|
|
54
|
-
|
|
55
|
-
- class that containts static methods to generate Promise based `awaiter` inside async function, to prevent race condition, including but not limited to:
|
|
56
|
-
behaviour:
|
|
57
|
-
|
|
58
|
-
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
59
|
-
|
|
60
|
-
<h2 id="signal">Signal</h2>
|
|
50
|
+
<h2 id="pingfifo">PingFIFO</h2>
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
can be subscribed by using [New$](#new$) or [NewDerived](#newderived);
|
|
64
|
-
for minimal total bundle size use `function` [NewSignal](#newSignal) instead;
|
|
52
|
+
```js
|
|
65
53
|
* @typedef {[callback:()=>(any|Promise<any>),debounce?:(number)]} queueFIFODetails
|
|
66
54
|
*/
|
|
67
|
-
a class for Queue;
|
|
68
|
-
function to auto queue callbacks that will be called `first in first out` style;
|
|
69
|
-
this class provides `QFIFO.makeQClass`;
|
|
70
55
|
|
|
71
56
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
72
57
|
|
|
73
|
-
<h2 id="
|
|
58
|
+
<h2 id="pingunique">PingUnique</h2>
|
|
74
59
|
|
|
75
|
-
- function to create `autosubscriber`;
|
|
76
60
|
- syntatic sugar for [$](#$);
|
|
77
61
|
// runs everytime signal.value changes;
|
|
78
62
|
return signal.value * 2;
|
|
79
63
|
// runs everytime signal.value changes;
|
|
80
64
|
console.log(signal.value);
|
|
81
65
|
// console.log(derived.value);
|
|
66
|
+
- a class for Queue;
|
|
82
67
|
new PingUnique(uniqueID, async () => {
|
|
83
|
-
this class provides `QUnique.makeQClass`;
|
|
84
68
|
|
|
85
69
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
86
70
|
|
|
87
|
-
<h2 id="newderived">NewDerived</h2>
|
|
88
|
-
|
|
89
|
-
- function to create `signal` that its value are derived from another `signal`;
|
|
90
71
|
- syntatic sugar for [Derived](#derived);
|
|
91
72
|
// runs everytime signal.value changes;
|
|
92
73
|
return signal.value * 2;
|
|
93
74
|
// runs everytime derived.value changes;
|
|
94
75
|
console.log(derived.value);
|
|
95
|
-
|
|
96
|
-
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
97
|
-
|
|
98
|
-
<h2 id="newpingfifo">NewPingFIFO</h2>
|
|
76
|
+
<h2 id="q">Q</h2>
|
|
99
77
|
|
|
100
|
-
-
|
|
78
|
+
- class that containts static methods to generate Promise based `awaiter` inside async function, to prevent race condition, including but not limited to:
|
|
101
|
-
behaviour:
|
|
102
|
-
this class provides `Q.makeQClass`;
|
|
103
79
|
|
|
104
80
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
105
81
|
|
|
106
|
-
<h2 id="
|
|
82
|
+
<h2 id="signal">Signal</h2>
|
|
107
83
|
|
|
108
|
-
-
|
|
84
|
+
- a class for creating signal;
|
|
109
85
|
// runs everytime signal.value changes;
|
|
110
86
|
return signal.value * 2;
|
|
111
87
|
// runs everytime signal.value changes;
|
|
112
88
|
console.log(signal.value);
|
|
113
89
|
|
|
114
90
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
115
91
|
|
|
116
|
-
<h2 id="
|
|
92
|
+
<h2 id="newqblock">NewQBlock</h2>
|
|
117
93
|
|
|
118
|
-
- function to create `signal`;
|
|
119
94
|
- syntatic sugar for [Signal](#signal);
|
|
120
95
|
// runs everytime signal.value changes;
|
|
121
96
|
return signal.value * 2;
|
|
122
97
|
// runs everytime signal.value changes;
|
|
123
98
|
console.log(signal.value);
|
|
99
|
+
- a function for Queue;
|
|
124
|
-
will wait next execution of the same `arg1`:`objectReferenceID`, without blocking other calls;
|
|
125
100
|
const objectReferenceID = 'yourUniqueID'; // can be anything, reference to object is preferable;
|
|
126
101
|
);
|
|
127
102
|
|
|
128
103
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
129
104
|
|
|
130
|
-
<h2 id="tryasync">
|
|
105
|
+
<h2 id="tryasync">TryAsync</h2>
|
|
131
106
|
|
|
132
107
|
- error as value for asynchronous operation
|
|
133
108
|
|
|
134
109
|
*) <sub>[go to exported list](#exported-api-and-type-list)</sub>
|
|
135
110
|
|
|
136
|
-
<h2 id="trysync">
|
|
111
|
+
<h2 id="trysync">TrySync</h2>
|
|
137
112
|
|
|
138
113
|
- error as value for synchronous operation
|
|
139
114
|
|
package/dev/index.mjs
CHANGED
|
@@ -24,5 +24,7 @@ new __JSDev({
|
|
|
24
24
|
'- `vivth` technically can run in any `js runtime`, since it uses non platform specific api;',
|
|
25
25
|
'- it is written specifically to be used as a primitives for javascript library or runtime, so there are no complex abstraction is, nor will be, added in `vivth` it self;',
|
|
26
26
|
'',
|
|
27
|
+
'### version',
|
|
28
|
+
'- 0.11.x: drop function wrapper for all classes, for better runtime performance',
|
|
27
29
|
],
|
|
28
30
|
}).run();
|
package/index.mjs
CHANGED
|
@@ -21,18 +21,18 @@
|
|
|
21
21
|
* - `vivth` technically can run in any `js runtime`, since it uses non platform specific api;
|
|
22
22
|
* - it is written specifically to be used as a primitives for javascript library or runtime, so there are no complex abstraction is, nor will be, added in `vivth` it self;
|
|
23
23
|
*
|
|
24
|
+
* ### version
|
|
25
|
+
* - 0.11.x: drop function wrapper for all classes, for better runtime performance
|
|
24
26
|
*/
|
|
25
27
|
export { $ } from './src/class/$.mjs';
|
|
26
28
|
export { Derived } from './src/class/Derived.mjs';
|
|
29
|
+
export { PingFIFO } from './src/class/PingFIFO.mjs';
|
|
30
|
+
export { PingUnique } from './src/class/PingUnique.mjs';
|
|
27
31
|
export { Q } from './src/class/Q.mjs';
|
|
28
32
|
export { Signal } from './src/class/Signal.mjs';
|
|
29
|
-
export {
|
|
30
|
-
export {
|
|
31
|
-
export {
|
|
32
|
-
export { NewPingUnique } from './src/function/NewPingUnique.mjs';
|
|
33
|
-
export { NewSignal } from './src/function/NewSignal.mjs';
|
|
34
|
-
export { tryAsync } from './src/function/tryAsync.export.mjs';
|
|
35
|
-
export { trySync } from './src/function/trySync.export.mjs';
|
|
33
|
+
export { NewQBlock } from './src/function/NewQBlock.mjs';
|
|
34
|
+
export { TryAsync } from './src/function/TryAsync.mjs';
|
|
35
|
+
export { TrySync } from './src/function/TrySync.mjs';
|
|
36
36
|
/**
|
|
37
|
-
* @typedef {{}|null|number|string|boolean|symbol|bigint|function}
|
|
37
|
+
* @typedef {{}|null|number|string|boolean|symbol|bigint|function} AnyButUndefined
|
|
38
38
|
*/
|
package/package.json
CHANGED
package/src/class/$.mjs
CHANGED
|
@@ -1,72 +1,82 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
-
import { NewPingFIFO } from '../function/NewPingFIFO.mjs';
|
|
4
3
|
import { isAsync } from '../common.mjs';
|
|
4
|
+
import { NewQBlock } from '../function/NewQBlock.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @description
|
|
8
8
|
* - a class to `autosubscribe` to an signal changes (`Derived` and `Signal` alike);
|
|
9
|
-
*
|
|
9
|
+
* ```js
|
|
10
|
+
* import { $, Derived, Signal } from 'vivth';
|
|
11
|
+
* const signal = new Signal(0);
|
|
12
|
+
* const derived = new Derived(async () =>{
|
|
13
|
+
* // runs everytime signal.value changes;
|
|
14
|
+
* return signal.value * 2;
|
|
15
|
+
* });
|
|
16
|
+
* const autosubscriber = new $(async ()=>{
|
|
17
|
+
* // runs everytime signal.value changes;
|
|
18
|
+
* console.log(signal.value);
|
|
19
|
+
* // console.log(derived.value);
|
|
20
|
+
* });
|
|
21
|
+
* signal.value = 1;
|
|
22
|
+
* ```
|
|
10
23
|
*/
|
|
11
24
|
export class $ {
|
|
12
25
|
/**
|
|
13
26
|
* @typedef {import('../class/Signal.mjs').Signal} Signal
|
|
14
27
|
*/
|
|
15
28
|
/**
|
|
16
|
-
* effects
|
|
17
29
|
* @type {Map<$, Set<Signal>>}
|
|
18
30
|
*/
|
|
19
|
-
static
|
|
31
|
+
static effects = new Map();
|
|
20
32
|
/**
|
|
21
|
-
* signalInstance
|
|
22
33
|
* @type {Map<Signal, Set<$>>}
|
|
23
34
|
*/
|
|
24
|
-
static
|
|
35
|
+
static mappedSignals = new Map();
|
|
25
36
|
/**
|
|
26
|
-
* activeSignalUponRegistering
|
|
27
37
|
* @type {Set<Signal>}
|
|
28
38
|
*/
|
|
29
|
-
static
|
|
39
|
+
static activeSignal = new Set();
|
|
30
40
|
/**
|
|
31
|
-
* isRegistering
|
|
32
41
|
* @type {boolean}
|
|
33
42
|
*/
|
|
34
|
-
static
|
|
43
|
+
static isRegistering = false;
|
|
35
44
|
/**
|
|
36
45
|
* @returns {void}
|
|
37
46
|
*/
|
|
38
47
|
remove$ = () => {
|
|
39
|
-
|
|
40
|
-
$.
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
NewQBlock(async () => {
|
|
49
|
+
$.effects.get(this)?.forEach((signalInstance) => {
|
|
50
|
+
$.mappedSignals.get(signalInstance).delete(this);
|
|
51
|
+
});
|
|
52
|
+
$.effects.set(this, new Set());
|
|
53
|
+
}, $);
|
|
43
54
|
};
|
|
44
55
|
/**
|
|
45
|
-
* @type {()=>void}
|
|
56
|
+
* @type {(arg:{remove$:$["remove$"]})=>void};
|
|
46
57
|
*/
|
|
47
58
|
effect;
|
|
48
59
|
/**
|
|
49
|
-
* @param {
|
|
60
|
+
* @param {(arg:{remove$:$["remove$"]})=>void} effect
|
|
50
61
|
*/
|
|
51
62
|
constructor(effect) {
|
|
52
63
|
this.effect = effect;
|
|
53
|
-
|
|
54
|
-
$.
|
|
64
|
+
NewQBlock(async () => {
|
|
65
|
+
$.isRegistering = true;
|
|
66
|
+
const check = this.effect({ remove$: this.remove$ });
|
|
55
67
|
if (isAsync(effect)) {
|
|
56
|
-
await
|
|
57
|
-
} else {
|
|
58
|
-
effect();
|
|
68
|
+
await check;
|
|
59
69
|
}
|
|
60
|
-
$.
|
|
61
|
-
const signalInstances = $.
|
|
62
|
-
$.
|
|
70
|
+
$.isRegistering = false;
|
|
71
|
+
const signalInstances = $.activeSignal;
|
|
72
|
+
$.effects.set(this, $.activeSignal);
|
|
63
73
|
signalInstances.forEach((signal) => {
|
|
64
|
-
if (!$.
|
|
65
|
-
$.
|
|
74
|
+
if (!$.mappedSignals.has(signal)) {
|
|
75
|
+
$.mappedSignals.set(signal, new Set());
|
|
66
76
|
}
|
|
67
|
-
$.
|
|
77
|
+
$.mappedSignals.get(signal).add(this);
|
|
68
78
|
});
|
|
69
|
-
$.
|
|
70
|
-
});
|
|
79
|
+
$.activeSignal = new Set();
|
|
80
|
+
}, $);
|
|
71
81
|
}
|
|
72
82
|
}
|
package/src/class/Derived.mjs
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
3
|
import { Signal } from './Signal.mjs';
|
|
4
|
-
import { New$ } from '../function//New$.mjs';
|
|
5
4
|
import { isAsync } from '../common.mjs';
|
|
5
|
+
import { $ } from './$.mjs';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @description
|
|
9
9
|
* - a class for creating signal which its value are derived from other signal (`Derived` and `Signal` alike);
|
|
10
|
-
*
|
|
11
|
-
*
|
|
10
|
+
* ```js
|
|
11
|
+
* import { $, Derived, Signal } from 'vivth';
|
|
12
|
+
* const signal = new Signal(0);
|
|
13
|
+
* const derived = new Derived(async () =>{
|
|
14
|
+
* // runs everytime signal.value changes;
|
|
15
|
+
* return signal.value * 2;
|
|
16
|
+
* });
|
|
17
|
+
* const autosubscriber = new $(async ()=>{
|
|
18
|
+
* // runs everytime derived.value changes;
|
|
19
|
+
* console.log(derived.value);
|
|
20
|
+
* });
|
|
21
|
+
* signal.value = 1;
|
|
22
|
+
* ```
|
|
12
23
|
*/
|
|
13
24
|
/**
|
|
14
25
|
* @template V
|
|
@@ -16,19 +27,24 @@ import { isAsync } from '../common.mjs';
|
|
|
16
27
|
*/
|
|
17
28
|
export class Derived extends Signal {
|
|
18
29
|
/**
|
|
19
|
-
* @param {()=>V} derivedFunction
|
|
30
|
+
* @param {(arg:{remove$:$["remove$"]})=>V} derivedFunction
|
|
20
31
|
*/
|
|
21
32
|
constructor(derivedFunction) {
|
|
22
|
-
|
|
23
|
-
super(0);
|
|
33
|
+
super(undefined);
|
|
24
34
|
const real = isAsync(derivedFunction)
|
|
25
|
-
?
|
|
26
|
-
|
|
35
|
+
? /**
|
|
36
|
+
* @param {{remove$:$["remove$"]}} options
|
|
37
|
+
*/
|
|
38
|
+
async (options) => {
|
|
39
|
+
super.value = await derivedFunction(options);
|
|
27
40
|
}
|
|
28
|
-
:
|
|
29
|
-
|
|
41
|
+
: /**
|
|
42
|
+
* @param {{remove$:$["remove$"]}} options
|
|
43
|
+
*/
|
|
44
|
+
(options) => {
|
|
45
|
+
super.value = derivedFunction(options);
|
|
30
46
|
};
|
|
31
|
-
|
|
47
|
+
new $(real);
|
|
32
48
|
}
|
|
33
49
|
/**
|
|
34
50
|
* @type {V}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { timeout } from '../common.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* ```js
|
|
8
|
+
* /**
|
|
9
|
+
* * @typedef {[callback:()=>(any|Promise<any>),debounce?:(number)]} queueFIFODetails
|
|
10
|
+
* *[blank]/
|
|
11
|
+
* ```
|
|
12
|
+
* - a class for Queue;
|
|
13
|
+
* - function to auto queue callbacks that will be called `first in first out` style;
|
|
14
|
+
* ```js
|
|
15
|
+
* // @ts-check
|
|
16
|
+
* import { PingFIFO } from 'vivth';
|
|
17
|
+
* const debounceMS = 0; // in miliseconds, optionals, default is 0;
|
|
18
|
+
* const handler = () =>{
|
|
19
|
+
* new PingFIFO(async () => {
|
|
20
|
+
* // your code
|
|
21
|
+
* }, debounceMS);
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
* - this class provides `QFIFO.makeQClass`;
|
|
25
|
+
* >- this method will setup `QFIFO` to use the inputed `queueArray`(as arg0) as centralized lookup for queue managed by `QFIFO`;
|
|
26
|
+
* >- usefull to modify this class for browser runtime, since `vivth` cannot just refer to window, you can just add `window["someobject"]`: `Array<queueFIFODetails>` as lookups;
|
|
27
|
+
*/
|
|
28
|
+
export class PingFIFO {
|
|
29
|
+
/**
|
|
30
|
+
* @param {queueFIFODetails[]} queueArray
|
|
31
|
+
* @returns {typeof PingFIFO}
|
|
32
|
+
*/
|
|
33
|
+
static makeQClass = (queueArray) => {
|
|
34
|
+
PingFIFO.#queue = queueArray;
|
|
35
|
+
return PingFIFO;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* @type {queueFIFODetails[]}
|
|
39
|
+
*/
|
|
40
|
+
static #queue = [];
|
|
41
|
+
/**
|
|
42
|
+
* @type {boolean}
|
|
43
|
+
*/
|
|
44
|
+
static #isRunning = false;
|
|
45
|
+
/**
|
|
46
|
+
* @param {()=>(any|Promise<any>)} callback
|
|
47
|
+
* @param {number} [debounce]
|
|
48
|
+
*/
|
|
49
|
+
constructor(callback, debounce = 0) {
|
|
50
|
+
PingFIFO.#push([callback, debounce]);
|
|
51
|
+
if (PingFIFO.#isRunning) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
PingFIFO.#run();
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* @param {queueFIFODetails} _queue
|
|
58
|
+
*/
|
|
59
|
+
static #push = (_queue) => {
|
|
60
|
+
PingFIFO.#queue.push(_queue);
|
|
61
|
+
};
|
|
62
|
+
static #run = async () => {
|
|
63
|
+
PingFIFO.#isRunning = true;
|
|
64
|
+
while (PingFIFO.#queue.length !== 0) {
|
|
65
|
+
const [callback, debounceMs = 0] = PingFIFO.#queue[0];
|
|
66
|
+
PingFIFO.#queue.shift();
|
|
67
|
+
await callback();
|
|
68
|
+
/**
|
|
69
|
+
* conditional debounce;
|
|
70
|
+
* queue FIFO messing up when have debouncer while `debounceMS` are set to 0;
|
|
71
|
+
*/
|
|
72
|
+
// if (debounceMs) {
|
|
73
|
+
await timeout(debounceMs);
|
|
74
|
+
// }
|
|
75
|
+
}
|
|
76
|
+
PingFIFO.#isRunning = false;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import { timeout } from '../common.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @description
|
|
7
|
+
* - a class for Queue;
|
|
8
|
+
* > - different `uniqueID`: called `first in first out` style;
|
|
9
|
+
* > - same `uniqueID`: will be grouped, only the already running callback and the last callback will be called;
|
|
10
|
+
* ```js
|
|
11
|
+
* // @ts-check
|
|
12
|
+
* import { PingUnique } from 'vivth';
|
|
13
|
+
* const uniqueID = 'yourUniqueID'; // can be anything, even a reference to an object;
|
|
14
|
+
* const debounceMS = 0; // in miliseconds, optionals, default is 0;
|
|
15
|
+
* const handler = () =>{
|
|
16
|
+
* new PingUnique(uniqueID, async () => {
|
|
17
|
+
* // your code
|
|
18
|
+
* }, debounceMS);
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
* - this class provides `QUnique.makeQClass`;
|
|
22
|
+
* >- this method will setup `QUnique` to use the inputed `queueMap`(as arg0) as centralized lookup for queue managed by `QUnique`;
|
|
23
|
+
* >- usefull to modify this class for browser runtime, since `vivth` cannot just refer to window, you can just add `window["someobject"]`: `Map<any, [()=>Promise<any>,number]>` as lookups;
|
|
24
|
+
*/
|
|
25
|
+
export class PingUnique {
|
|
26
|
+
/**
|
|
27
|
+
* @param {Map<any, [()=>Promise<void>,number]>} queueMap
|
|
28
|
+
* @returns {typeof PingUnique}
|
|
29
|
+
*/
|
|
30
|
+
static makeQClass = (queueMap) => {
|
|
31
|
+
PingUnique.#queue = queueMap;
|
|
32
|
+
return PingUnique;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @type {Map<any, [()=>Promise<void>,number]>}
|
|
36
|
+
*/
|
|
37
|
+
static #queue = new Map();
|
|
38
|
+
/**
|
|
39
|
+
* @type {boolean}
|
|
40
|
+
*/
|
|
41
|
+
static #isRunning = false;
|
|
42
|
+
/**
|
|
43
|
+
* @param {any} id
|
|
44
|
+
* @param {()=>Promise<void>} callback
|
|
45
|
+
* @param {number} [debounceMS]
|
|
46
|
+
*/
|
|
47
|
+
constructor(id, callback, debounceMS = 0) {
|
|
48
|
+
PingUnique.#push(id, callback, debounceMS);
|
|
49
|
+
if (!PingUnique.#isRunning) {
|
|
50
|
+
PingUnique.#run();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* @param {any} id
|
|
55
|
+
* @param {()=>Promise<void>} callback
|
|
56
|
+
* @param {number} debounceMS
|
|
57
|
+
*/
|
|
58
|
+
static #push = (id, callback, debounceMS) => {
|
|
59
|
+
PingUnique.#queue.set(id, [callback, debounceMS ? debounceMS : 0]);
|
|
60
|
+
};
|
|
61
|
+
static #run = async () => {
|
|
62
|
+
PingUnique.#isRunning = true;
|
|
63
|
+
const keysIterator = PingUnique.#queue.keys();
|
|
64
|
+
let keys = keysIterator.next();
|
|
65
|
+
while (!keys.done) {
|
|
66
|
+
const key = keys.value;
|
|
67
|
+
const q = PingUnique.#queue.get(key);
|
|
68
|
+
if (!q) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const [callback, debounce] = q;
|
|
72
|
+
PingUnique.#queue.delete(key);
|
|
73
|
+
/**
|
|
74
|
+
* debounce anyway;
|
|
75
|
+
* queue with unique id have characteristic of messing up when have no debouncer;
|
|
76
|
+
* especially when request comes too fast;
|
|
77
|
+
*/
|
|
78
|
+
await timeout(debounce);
|
|
79
|
+
await callback();
|
|
80
|
+
keys = keysIterator.next();
|
|
81
|
+
}
|
|
82
|
+
PingUnique.#isRunning = false;
|
|
83
|
+
};
|
|
84
|
+
}
|
package/src/class/Q.mjs
CHANGED
|
@@ -25,16 +25,26 @@
|
|
|
25
25
|
* - behaviour:
|
|
26
26
|
* > - `fifo`: call all queued callback `first in first out` style;
|
|
27
27
|
* > - `unique`: call all queued callback with the same `uniqueID` `first in first out` style, if the `uniqueID` is different it will be called in parallel;
|
|
28
|
+
* - this class provides `Q.makeQClass`;
|
|
29
|
+
* >- this method will setup `Q` to use the inputed `uniqueMap`(as arg0) as centralized lookup for queue managed by `Q`;
|
|
30
|
+
* >- usefull to modify this class for browser runtime, since `vivth` cannot just refer to window, you can just add `window["someobject"]`: `Array<Map<any, Promise<any>>>` as lookups;
|
|
28
31
|
*/
|
|
29
32
|
export class Q {
|
|
30
33
|
/**
|
|
31
|
-
* @
|
|
34
|
+
* @param {Map<any, Promise<any>>} uniqueMap
|
|
35
|
+
* @returns {typeof Q}
|
|
36
|
+
*/
|
|
37
|
+
static makeQClass = (uniqueMap) => {
|
|
38
|
+
Q.#unique = uniqueMap;
|
|
39
|
+
return Q;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* @typedef {import('../types/AnyButUndefined.type.mjs').AnyButUndefined} anyButUndefined
|
|
32
43
|
*/
|
|
33
44
|
/**
|
|
34
|
-
* @private
|
|
35
45
|
* @type {Promise<void>}
|
|
36
46
|
*/
|
|
37
|
-
static
|
|
47
|
+
static #fifo = Promise.resolve();
|
|
38
48
|
/**
|
|
39
49
|
* Blocks execution for subsequent calls until the current one finishes.
|
|
40
50
|
* @returns {Promise<{resume:()=>void}>} Resolves when it's safe to proceed, returning a cleanup function
|
|
@@ -44,8 +54,8 @@ export class Q {
|
|
|
44
54
|
const next = new Promise((resolve) => {
|
|
45
55
|
resolveFn = resolve;
|
|
46
56
|
});
|
|
47
|
-
const prev = Q
|
|
48
|
-
Q
|
|
57
|
+
const prev = Q.#fifo;
|
|
58
|
+
Q.#fifo = next;
|
|
49
59
|
await prev;
|
|
50
60
|
return {
|
|
51
61
|
resume: () => {
|
|
@@ -56,7 +66,7 @@ export class Q {
|
|
|
56
66
|
/**
|
|
57
67
|
* @type {Map<any, Promise<any>>}
|
|
58
68
|
*/
|
|
59
|
-
static
|
|
69
|
+
static #unique = new Map();
|
|
60
70
|
/**
|
|
61
71
|
* Ensures that each id has only one task running at a time.
|
|
62
72
|
* Calls with the same id will wait for the previous call to finish.
|
|
@@ -64,23 +74,23 @@ export class Q {
|
|
|
64
74
|
* @returns {Promise<{resume:()=>void}>} Resolves when it's safe to proceed for the given id, returning a cleanup function
|
|
65
75
|
*/
|
|
66
76
|
static unique = async (id) => {
|
|
67
|
-
if (!Q.
|
|
68
|
-
Q.
|
|
77
|
+
if (!Q.#unique.has(id)) {
|
|
78
|
+
Q.#unique.set(id, Promise.resolve());
|
|
69
79
|
let resolveFn;
|
|
70
80
|
const next = new Promise((resolve) => {
|
|
71
81
|
resolveFn = resolve;
|
|
72
82
|
});
|
|
73
|
-
const prev = Q.
|
|
74
|
-
Q.
|
|
83
|
+
const prev = Q.#unique.get(id);
|
|
84
|
+
Q.#unique.set(id, next);
|
|
75
85
|
await prev;
|
|
76
86
|
return {
|
|
77
87
|
resume: () => {
|
|
78
88
|
resolveFn();
|
|
79
|
-
Q.
|
|
89
|
+
Q.#unique.delete(id);
|
|
80
90
|
},
|
|
81
91
|
};
|
|
82
92
|
} else {
|
|
83
|
-
const prev = Q.
|
|
93
|
+
const prev = Q.#unique.get(id);
|
|
84
94
|
await prev;
|
|
85
95
|
return await Q.unique(id);
|
|
86
96
|
}
|