@woosh/meep-engine 2.49.4 → 2.49.6
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/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
export declare class LoadingCache<K,V>{
|
|
2
|
-
constructor(options:{
|
|
1
|
+
export declare class LoadingCache<K, V> {
|
|
2
|
+
constructor(options: {
|
|
3
3
|
maxWeight?: number,
|
|
4
4
|
keyWeigher?: (key: K) => number,
|
|
5
5
|
valueWeigher?: (value: V) => number,
|
|
6
6
|
keyHashFunction?: (key: K) => number,
|
|
7
7
|
keyEqualityFunction?: (a: K, b: K) => boolean,
|
|
8
8
|
capacity?: number,
|
|
9
|
-
timeToLive?:number,
|
|
10
|
-
load:(key:K)=> Promise<V
|
|
9
|
+
timeToLive?: number,
|
|
10
|
+
load: (key: K) => Promise<V>,
|
|
11
|
+
retryFailed?: boolean
|
|
11
12
|
})
|
|
12
13
|
|
|
13
|
-
invalidate(key:K):void
|
|
14
|
+
invalidate(key: K): void
|
|
14
15
|
|
|
15
|
-
clear():void
|
|
16
|
+
clear(): void
|
|
16
17
|
|
|
17
|
-
get(key:K):Promise<V>
|
|
18
|
+
get(key: K): Promise<V>
|
|
18
19
|
}
|
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
import { Cache } from "./Cache.js";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @template
|
|
6
|
+
* @template R
|
|
7
7
|
*/
|
|
8
8
|
class Record {
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @param {
|
|
10
|
+
* @template R
|
|
11
|
+
* @param {R} value
|
|
12
12
|
* @param {number} time
|
|
13
13
|
*/
|
|
14
14
|
constructor(value, time) {
|
|
15
15
|
this.value = value;
|
|
16
16
|
this.time = time;
|
|
17
|
+
this.failed = false;
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -38,6 +39,12 @@ export class LoadingCache {
|
|
|
38
39
|
*/
|
|
39
40
|
#load
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
*
|
|
44
|
+
* @type {boolean}
|
|
45
|
+
*/
|
|
46
|
+
#policyRetryFailed = true;
|
|
47
|
+
|
|
41
48
|
/**
|
|
42
49
|
* @see {@link Cache} for more details on what each parameter means
|
|
43
50
|
* @param maxWeight
|
|
@@ -48,6 +55,7 @@ export class LoadingCache {
|
|
|
48
55
|
* @param capacity
|
|
49
56
|
* @param {number} [timeToLive] in seconds
|
|
50
57
|
* @param load
|
|
58
|
+
* @param {boolean} [retryFailed]
|
|
51
59
|
*/
|
|
52
60
|
constructor({
|
|
53
61
|
maxWeight,
|
|
@@ -57,7 +65,8 @@ export class LoadingCache {
|
|
|
57
65
|
keyEqualityFunction,
|
|
58
66
|
capacity,
|
|
59
67
|
timeToLive = DEFAULT_TIME_TO_LIVE,
|
|
60
|
-
load
|
|
68
|
+
load,
|
|
69
|
+
retryFailed = true
|
|
61
70
|
}) {
|
|
62
71
|
|
|
63
72
|
this.#internal = new Cache({
|
|
@@ -71,6 +80,7 @@ export class LoadingCache {
|
|
|
71
80
|
|
|
72
81
|
this.#timeToLive = timeToLive;
|
|
73
82
|
this.#load = load;
|
|
83
|
+
this.#policyRetryFailed = retryFailed;
|
|
74
84
|
}
|
|
75
85
|
|
|
76
86
|
/**
|
|
@@ -96,17 +106,36 @@ export class LoadingCache {
|
|
|
96
106
|
async get(key) {
|
|
97
107
|
const currentTime = performance.now() * 1e-3;
|
|
98
108
|
|
|
109
|
+
/**
|
|
110
|
+
*
|
|
111
|
+
* @type {Record<Promise<V>>}
|
|
112
|
+
*/
|
|
99
113
|
let record = this.#internal.get(key);
|
|
100
114
|
|
|
101
|
-
if (record === null
|
|
115
|
+
if (record === null
|
|
116
|
+
|| (record.time + this.#timeToLive) < currentTime // timeout
|
|
117
|
+
|| (record.failed && this.#policyRetryFailed) // load failed and we're configured to retry
|
|
118
|
+
) {
|
|
119
|
+
|
|
120
|
+
// record needs to be loaded
|
|
102
121
|
|
|
103
|
-
|
|
104
|
-
|
|
122
|
+
let promise;
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
promise = this.#load(key);
|
|
126
|
+
}catch (e){
|
|
127
|
+
promise = Promise.reject(e);
|
|
128
|
+
}
|
|
105
129
|
|
|
106
130
|
record = new Record(promise, currentTime);
|
|
107
131
|
|
|
108
132
|
this.#internal.put(key, record);
|
|
109
133
|
|
|
134
|
+
promise.catch(() => {
|
|
135
|
+
// mark as failure
|
|
136
|
+
record.failed = true;
|
|
137
|
+
});
|
|
138
|
+
|
|
110
139
|
}
|
|
111
140
|
|
|
112
141
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { LoadingCache } from "./LoadingCache.js";
|
|
2
|
+
import { delay } from "../process/delay.js";
|
|
3
|
+
|
|
4
|
+
test("successful load", async () => {
|
|
5
|
+
const cache = new LoadingCache({
|
|
6
|
+
async load(key) {
|
|
7
|
+
return 17;
|
|
8
|
+
}
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
expect(await cache.get(1)).toEqual(17);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("record reuse", async () => {
|
|
15
|
+
const load = jest.fn(async () => 17);
|
|
16
|
+
|
|
17
|
+
const cache = new LoadingCache({
|
|
18
|
+
load
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
expect(await cache.get(1)).toEqual(17);
|
|
22
|
+
expect(await cache.get(1)).toEqual(17);
|
|
23
|
+
|
|
24
|
+
expect(load).toHaveBeenCalledTimes(1);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test("timeout reload reuse", async () => {
|
|
28
|
+
|
|
29
|
+
const values = [3, 5, 11];
|
|
30
|
+
|
|
31
|
+
const load = jest.fn(async () => values.pop());
|
|
32
|
+
|
|
33
|
+
const cache = new LoadingCache({
|
|
34
|
+
load,
|
|
35
|
+
timeToLive: 0.00001
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
expect(await cache.get(1)).toEqual(11);
|
|
39
|
+
|
|
40
|
+
await delay(1);
|
|
41
|
+
|
|
42
|
+
expect(await cache.get(1)).toEqual(5);
|
|
43
|
+
|
|
44
|
+
await delay(1);
|
|
45
|
+
|
|
46
|
+
expect(await cache.get(1)).toEqual(3);
|
|
47
|
+
});
|