async-reactivity 2.0.21 → 2.0.23
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/lib/computed.js +10 -3
- package/lib/computed.test.js +33 -0
- package/package.json +1 -1
- package/src/computed.test.ts +36 -0
- package/src/computed.ts +12 -5
- package/types/computed.d.ts +3 -2
- package/types/computed.d.ts.map +1 -1
package/lib/computed.js
CHANGED
|
@@ -9,7 +9,6 @@ var ComputedState;
|
|
|
9
9
|
ComputedState[ComputedState["Uncertain"] = 2] = "Uncertain";
|
|
10
10
|
ComputedState[ComputedState["Computing"] = 3] = "Computing";
|
|
11
11
|
})(ComputedState || (ComputedState = {}));
|
|
12
|
-
;
|
|
13
12
|
class CircularDependencyError extends Error {
|
|
14
13
|
}
|
|
15
14
|
export default class Computed extends Tracker {
|
|
@@ -21,6 +20,7 @@ export default class Computed extends Tracker {
|
|
|
21
20
|
computePromiseActions;
|
|
22
21
|
lastComputeAttemptPromise;
|
|
23
22
|
deferrer;
|
|
23
|
+
abortController;
|
|
24
24
|
constructor(getter, isEqual = (defaultIsEqual), timeToLive) {
|
|
25
25
|
super();
|
|
26
26
|
this.getter = getter;
|
|
@@ -70,9 +70,13 @@ export default class Computed extends Tracker {
|
|
|
70
70
|
return this._value;
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
+
else if (this.state === ComputedState.Computing) {
|
|
74
|
+
this.abortController?.abort();
|
|
75
|
+
}
|
|
73
76
|
this.state = ComputedState.Computing;
|
|
74
77
|
this.clearDependencies(true);
|
|
75
|
-
|
|
78
|
+
this.abortController = new AbortController();
|
|
79
|
+
const newValue = this.getter(this.trackDependency, this._value, this.abortController.signal);
|
|
76
80
|
if (this.isEqual(newValue, this._value)) {
|
|
77
81
|
this.handlePromiseThen(this.lastComputeAttemptPromise, this._value);
|
|
78
82
|
this.validateDependents();
|
|
@@ -120,6 +124,7 @@ export default class Computed extends Tracker {
|
|
|
120
124
|
finalizeComputing() {
|
|
121
125
|
this.state = ComputedState.Valid;
|
|
122
126
|
this.lastComputeAttemptPromise = undefined;
|
|
127
|
+
this.abortController = undefined;
|
|
123
128
|
this.prepareComputePromise();
|
|
124
129
|
}
|
|
125
130
|
invalidate() {
|
|
@@ -134,7 +139,9 @@ export default class Computed extends Tracker {
|
|
|
134
139
|
}
|
|
135
140
|
forceInvalidate() {
|
|
136
141
|
this.invalidate();
|
|
137
|
-
this.state
|
|
142
|
+
if (this.state !== ComputedState.Computing) {
|
|
143
|
+
this.state = ComputedState.Invalid;
|
|
144
|
+
}
|
|
138
145
|
}
|
|
139
146
|
validate(dependency) {
|
|
140
147
|
this.dependencies.set(dependency, false);
|
package/lib/computed.test.js
CHANGED
|
@@ -130,6 +130,22 @@ describe('computed', function () {
|
|
|
130
130
|
assert.strictEqual(c.value, 6);
|
|
131
131
|
assert.strictEqual(gate, 2);
|
|
132
132
|
});
|
|
133
|
+
it('compute and abort when forced', async function () {
|
|
134
|
+
let gate = 0;
|
|
135
|
+
const b = new Computed(async (_value, _previousValue, abortSignal) => {
|
|
136
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
137
|
+
if (abortSignal.aborted) {
|
|
138
|
+
gate++;
|
|
139
|
+
throw new Error();
|
|
140
|
+
}
|
|
141
|
+
return 5;
|
|
142
|
+
});
|
|
143
|
+
const v = b.value;
|
|
144
|
+
await new Promise(resolve => setTimeout(resolve, 5));
|
|
145
|
+
b.forceInvalidate();
|
|
146
|
+
assert.strictEqual(await v, 5);
|
|
147
|
+
assert.strictEqual(gate, 1);
|
|
148
|
+
});
|
|
133
149
|
it('isEqual', function () {
|
|
134
150
|
const a = new Ref(1);
|
|
135
151
|
const b = new Computed((value) => {
|
|
@@ -186,6 +202,23 @@ describe('async computed', function () {
|
|
|
186
202
|
a.value = 8;
|
|
187
203
|
assert.strictEqual(await b.value, 13);
|
|
188
204
|
});
|
|
205
|
+
it('dependency changed while computing - abortSignal', async function () {
|
|
206
|
+
const a = new Ref(5);
|
|
207
|
+
let gate = 0;
|
|
208
|
+
const b = new Computed(async (value, _previousValue, abortSignal) => {
|
|
209
|
+
const dep = value(a);
|
|
210
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
211
|
+
if (abortSignal.aborted) {
|
|
212
|
+
throw new Error();
|
|
213
|
+
}
|
|
214
|
+
gate++;
|
|
215
|
+
return dep + 5;
|
|
216
|
+
});
|
|
217
|
+
b.value; // trigger compute
|
|
218
|
+
a.value = 8;
|
|
219
|
+
await b.value;
|
|
220
|
+
assert.strictEqual(gate, 1);
|
|
221
|
+
});
|
|
189
222
|
it('old dependency changed while computing', async function () {
|
|
190
223
|
let gate = 0;
|
|
191
224
|
const a = new Ref(5);
|
package/package.json
CHANGED
package/src/computed.test.ts
CHANGED
|
@@ -153,6 +153,24 @@ describe('computed', function () {
|
|
|
153
153
|
assert.strictEqual(gate, 2);
|
|
154
154
|
});
|
|
155
155
|
|
|
156
|
+
it('compute and abort when forced', async function () {
|
|
157
|
+
let gate = 0;
|
|
158
|
+
const b = new Computed(async (_value, _previousValue, abortSignal) => {
|
|
159
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
160
|
+
if (abortSignal.aborted) {
|
|
161
|
+
gate++;
|
|
162
|
+
throw new Error();
|
|
163
|
+
}
|
|
164
|
+
return 5;
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const v = b.value;
|
|
168
|
+
await new Promise(resolve => setTimeout(resolve, 5));
|
|
169
|
+
b.forceInvalidate();
|
|
170
|
+
assert.strictEqual(await v, 5);
|
|
171
|
+
assert.strictEqual(gate, 1);
|
|
172
|
+
});
|
|
173
|
+
|
|
156
174
|
it('isEqual', function() {
|
|
157
175
|
const a = new Ref(1);
|
|
158
176
|
const b = new Computed((value) => {
|
|
@@ -219,6 +237,24 @@ describe('async computed', function () {
|
|
|
219
237
|
assert.strictEqual(await b.value, 13);
|
|
220
238
|
});
|
|
221
239
|
|
|
240
|
+
it('dependency changed while computing - abortSignal', async function () {
|
|
241
|
+
const a = new Ref(5);
|
|
242
|
+
let gate = 0;
|
|
243
|
+
const b = new Computed(async (value, _previousValue, abortSignal) => {
|
|
244
|
+
const dep = value(a);
|
|
245
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
246
|
+
if (abortSignal.aborted) {
|
|
247
|
+
throw new Error();
|
|
248
|
+
}
|
|
249
|
+
gate++;
|
|
250
|
+
return dep + 5;
|
|
251
|
+
});
|
|
252
|
+
b.value; // trigger compute
|
|
253
|
+
a.value = 8;
|
|
254
|
+
await b.value;
|
|
255
|
+
assert.strictEqual(gate, 1);
|
|
256
|
+
});
|
|
257
|
+
|
|
222
258
|
it('old dependency changed while computing', async function () {
|
|
223
259
|
let gate = 0;
|
|
224
260
|
const a = new Ref(5);
|
package/src/computed.ts
CHANGED
|
@@ -6,15 +6,15 @@ import { Deferrer } from "./deferrer.js";
|
|
|
6
6
|
import { debounce } from 'lodash-es';
|
|
7
7
|
|
|
8
8
|
export declare type TrackValue = <T>(dependency: Dependency<T>) => T;
|
|
9
|
-
export declare type ComputeFunc<T> = (value: TrackValue, previousValue
|
|
10
|
-
export declare type ComputeFuncScoped<T1, T2> = (value: TrackValue, scope: T1, previousValue
|
|
9
|
+
export declare type ComputeFunc<T> = (value: TrackValue, previousValue: T | undefined, abortSignal: AbortSignal) => T;
|
|
10
|
+
export declare type ComputeFuncScoped<T1, T2> = (value: TrackValue, scope: T1, previousValue: T2 | undefined, abortSignal: AbortSignal) => T2;
|
|
11
11
|
|
|
12
12
|
enum ComputedState {
|
|
13
13
|
Invalid,
|
|
14
14
|
Valid,
|
|
15
15
|
Uncertain,
|
|
16
16
|
Computing
|
|
17
|
-
}
|
|
17
|
+
}
|
|
18
18
|
|
|
19
19
|
class CircularDependencyError extends Error { }
|
|
20
20
|
|
|
@@ -27,6 +27,7 @@ export default class Computed<T> extends Tracker<T> implements Dependent, Depend
|
|
|
27
27
|
private computePromiseActions?: { resolve: Function, reject: Function };
|
|
28
28
|
private lastComputeAttemptPromise?: Promise<void>;
|
|
29
29
|
private deferrer?: Deferrer;
|
|
30
|
+
private abortController?: AbortController;
|
|
30
31
|
|
|
31
32
|
constructor(getter: ComputeFunc<T>, isEqual = defaultIsEqual<T>, timeToLive?: number) {
|
|
32
33
|
super();
|
|
@@ -80,12 +81,15 @@ export default class Computed<T> extends Tracker<T> implements Dependent, Depend
|
|
|
80
81
|
this.validateDependents();
|
|
81
82
|
return this._value!;
|
|
82
83
|
}
|
|
84
|
+
} else if (this.state === ComputedState.Computing) {
|
|
85
|
+
this.abortController?.abort();
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
this.state = ComputedState.Computing;
|
|
86
89
|
this.clearDependencies(true);
|
|
90
|
+
this.abortController = new AbortController();
|
|
87
91
|
|
|
88
|
-
const newValue: T = this.getter(this.trackDependency, this._value);
|
|
92
|
+
const newValue: T = this.getter(this.trackDependency, this._value, this.abortController.signal);
|
|
89
93
|
if (this.isEqual(newValue, this._value!)) {
|
|
90
94
|
this.handlePromiseThen(this.lastComputeAttemptPromise!, this._value);
|
|
91
95
|
this.validateDependents();
|
|
@@ -137,6 +141,7 @@ export default class Computed<T> extends Tracker<T> implements Dependent, Depend
|
|
|
137
141
|
private finalizeComputing() {
|
|
138
142
|
this.state = ComputedState.Valid;
|
|
139
143
|
this.lastComputeAttemptPromise = undefined;
|
|
144
|
+
this.abortController = undefined;
|
|
140
145
|
this.prepareComputePromise();
|
|
141
146
|
}
|
|
142
147
|
|
|
@@ -152,7 +157,9 @@ export default class Computed<T> extends Tracker<T> implements Dependent, Depend
|
|
|
152
157
|
|
|
153
158
|
public forceInvalidate() {
|
|
154
159
|
this.invalidate();
|
|
155
|
-
this.state
|
|
160
|
+
if (this.state !== ComputedState.Computing) {
|
|
161
|
+
this.state = ComputedState.Invalid;
|
|
162
|
+
}
|
|
156
163
|
}
|
|
157
164
|
|
|
158
165
|
public validate(dependency: Dependency<any>) {
|
package/types/computed.d.ts
CHANGED
|
@@ -3,8 +3,8 @@ import Dependent from "./dependent.js";
|
|
|
3
3
|
import Tracker from "./tracker.js";
|
|
4
4
|
import defaultIsEqual from "./defaultIsEqual.js";
|
|
5
5
|
export declare type TrackValue = <T>(dependency: Dependency<T>) => T;
|
|
6
|
-
export declare type ComputeFunc<T> = (value: TrackValue, previousValue
|
|
7
|
-
export declare type ComputeFuncScoped<T1, T2> = (value: TrackValue, scope: T1, previousValue
|
|
6
|
+
export declare type ComputeFunc<T> = (value: TrackValue, previousValue: T | undefined, abortSignal: AbortSignal) => T;
|
|
7
|
+
export declare type ComputeFuncScoped<T1, T2> = (value: TrackValue, scope: T1, previousValue: T2 | undefined, abortSignal: AbortSignal) => T2;
|
|
8
8
|
export default class Computed<T> extends Tracker<T> implements Dependent, Dependency<T> {
|
|
9
9
|
getter: ComputeFunc<T>;
|
|
10
10
|
isEqual: typeof defaultIsEqual<T>;
|
|
@@ -14,6 +14,7 @@ export default class Computed<T> extends Tracker<T> implements Dependent, Depend
|
|
|
14
14
|
private computePromiseActions?;
|
|
15
15
|
private lastComputeAttemptPromise?;
|
|
16
16
|
private deferrer?;
|
|
17
|
+
private abortController?;
|
|
17
18
|
constructor(getter: ComputeFunc<T>, isEqual?: (v1: T, v2: T) => boolean, timeToLive?: number);
|
|
18
19
|
private prepareComputePromise;
|
|
19
20
|
get value(): T;
|
package/types/computed.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,iBAAiB,CAAC;AACzC,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAIjD,MAAM,CAAC,OAAO,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACrE,MAAM,CAAC,OAAO,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,aAAa,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"computed.d.ts","sourceRoot":"","sources":["../src/computed.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,iBAAiB,CAAC;AACzC,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,cAAc,MAAM,qBAAqB,CAAC;AAIjD,MAAM,CAAC,OAAO,MAAM,UAAU,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;AACrE,MAAM,CAAC,OAAO,MAAM,WAAW,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,GAAG,SAAS,EAAE,WAAW,EAAE,WAAW,KAAK,CAAC,CAAC;AACtH,MAAM,CAAC,OAAO,MAAM,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,GAAG,SAAS,EAAE,WAAW,EAAE,WAAW,KAAK,EAAE,CAAC;AAW9I,MAAM,CAAC,OAAO,OAAO,QAAQ,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAE,YAAW,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC;IACnF,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACvB,OAAO,EAAE,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC;IAClC,OAAO,CAAC,KAAK,CAAyB;IACtC,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,cAAc,CAAC,CAAe;IACtC,OAAO,CAAC,qBAAqB,CAAC,CAA0C;IACxE,OAAO,CAAC,yBAAyB,CAAC,CAAgB;IAClD,OAAO,CAAC,QAAQ,CAAC,CAAW;IAC5B,OAAO,CAAC,eAAe,CAAC,CAAkB;gBAE9B,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,4BAAoB,EAAE,UAAU,CAAC,EAAE,MAAM;IAepF,OAAO,CAAC,qBAAqB;IAS7B,IAAW,KAAK,IAAI,CAAC,CAMpB;IAED,OAAO,CAAC,OAAO;IA6Cf,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,eAAe,CAAwC;IAE/D,OAAO,CAAC,iBAAiB;IAOlB,UAAU;IAUV,eAAe;IAOf,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC;IAI3C,OAAO,CAAC,kBAAkB;IAMnB,eAAe,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,gBAAoB,GAAG,IAAI;IAKxE,KAAK;IAQL,OAAO;CAGjB"}
|