reactronic 0.92.25008 → 0.92.25010
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 +80 -83
- package/build/dist/source/Clock.d.ts +2 -0
- package/build/dist/source/Clock.js +18 -6
- package/build/dist/source/Options.d.ts +3 -3
- package/build/dist/source/Options.js +3 -3
- package/build/dist/source/ReactiveLoop.d.ts +7 -0
- package/build/dist/source/{Reaction.js → ReactiveLoop.js} +5 -5
- package/build/dist/source/ReactiveSystem.js +3 -3
- package/build/dist/source/api.d.ts +1 -1
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/core/Indicator.d.ts +1 -1
- package/build/dist/source/core/Indicator.js +2 -2
- package/build/dist/source/core/Operation.js +13 -13
- package/build/dist/source/core/Transaction.d.ts +2 -2
- package/build/dist/source/core/Transaction.js +18 -18
- package/package.json +1 -1
- package/build/dist/source/Reaction.d.ts +0 -7
package/README.md
CHANGED
|
@@ -27,14 +27,14 @@ concepts:
|
|
|
27
27
|
|
|
28
28
|
- **Observable Objects** - a set of objects that store
|
|
29
29
|
data of an application (state);
|
|
30
|
-
- **Atomic
|
|
30
|
+
- **Atomic Function** - a function that makes changes in
|
|
31
31
|
observable objects in atomic way ("all or nothing");
|
|
32
|
-
- **Reactive
|
|
33
|
-
(re-)
|
|
34
|
-
|
|
35
|
-
- **Cached
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
- **Reactive Function** - a function that is
|
|
33
|
+
(re-)executed in response to changes made by atomic
|
|
34
|
+
actions;
|
|
35
|
+
- **Cached Function** - a function which result is
|
|
36
|
+
remembered and, if becomes obsolete, causes function
|
|
37
|
+
to re-execute on-demand.
|
|
38
38
|
|
|
39
39
|
Demo application built with Reactronic: https://nevod.io/#/playground.
|
|
40
40
|
Source code of the demo: https://gitlab.com/nezaboodka/nevod.web.public/-/blob/master/README.md.
|
|
@@ -50,13 +50,13 @@ class Demo extends ObservableObject {
|
|
|
50
50
|
name: string = 'Nezaboodka Software'
|
|
51
51
|
email: string = 'contact@nezaboodka.com'
|
|
52
52
|
|
|
53
|
-
@
|
|
53
|
+
@atomic
|
|
54
54
|
saveContact(name: string, email: string): void {
|
|
55
55
|
this.name = name
|
|
56
56
|
this.email = email
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
@
|
|
59
|
+
@reactive
|
|
60
60
|
printContact(): void {
|
|
61
61
|
// depends on `name` and `email` and reacts to their changes
|
|
62
62
|
if (this.email.indexOf('@') >= 0)
|
|
@@ -68,11 +68,11 @@ class Demo extends ObservableObject {
|
|
|
68
68
|
|
|
69
69
|
In the example above, `Demo` is an observable object,
|
|
70
70
|
meaning that access to its fields are seamlessly tracked
|
|
71
|
-
to determine dependent reactive
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
to determine dependent reactive and cached functions.
|
|
72
|
+
Reactive function `printContact` reads `name` and `email`
|
|
73
|
+
fields, thus depends on them. It is executed automatically
|
|
74
|
+
in response to changes of these fields made by the atomic
|
|
75
|
+
function `saveContact`.
|
|
76
76
|
|
|
77
77
|
Here is an example of a cached result that is
|
|
78
78
|
(re-)computed on-demand:
|
|
@@ -87,7 +87,7 @@ class Demo extends ObservableObject {
|
|
|
87
87
|
return this.name + ' <' + this.email + '>'
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
@
|
|
90
|
+
@reactive
|
|
91
91
|
printContact(): void {
|
|
92
92
|
if (this.contact !== '')
|
|
93
93
|
Console.log(this.contact)
|
|
@@ -100,8 +100,8 @@ computed from source fields `name` and `email`. Once
|
|
|
100
100
|
computed, the result is cached and is reused until
|
|
101
101
|
source fields `name` and `email` are changed. Once
|
|
102
102
|
source fields changed, `contact` result becomes obsolete,
|
|
103
|
-
thus causing execution of depending reactive
|
|
104
|
-
`printContact`. When function of reactive
|
|
103
|
+
thus causing execution of depending reactive function
|
|
104
|
+
`printContact`. When function of reactive function
|
|
105
105
|
`printContact` runs it reads `contact` and causes its
|
|
106
106
|
re-computation.
|
|
107
107
|
|
|
@@ -124,19 +124,18 @@ In the example above, the class `MyModel` is based on
|
|
|
124
124
|
Reactronic's `ObservableObject` class and all its
|
|
125
125
|
properties `url`, `content`, and `timestamp` are hooked.
|
|
126
126
|
|
|
127
|
-
## Atomic
|
|
127
|
+
## Atomic Function
|
|
128
128
|
|
|
129
|
-
Atomic
|
|
129
|
+
Atomic function makes changes in observable objects
|
|
130
130
|
in atomic (transactional) way, thus provoking execution
|
|
131
|
-
of dependent reactive
|
|
132
|
-
|
|
133
|
-
instrumented with hooks to provide transparent atomicity
|
|
131
|
+
of dependent reactive and cached functions. Atomic
|
|
132
|
+
function is instrumented with hooks to provide transparent atomicity
|
|
134
133
|
(by implicit context switching and isolation).
|
|
135
134
|
|
|
136
135
|
``` typescript
|
|
137
136
|
class MyModel extends ObservableObject {
|
|
138
137
|
// ...
|
|
139
|
-
@
|
|
138
|
+
@atomic
|
|
140
139
|
async load(url: string): Promise<void> {
|
|
141
140
|
this.url = url
|
|
142
141
|
this.content = await fetch(url)
|
|
@@ -145,50 +144,50 @@ class MyModel extends ObservableObject {
|
|
|
145
144
|
}
|
|
146
145
|
```
|
|
147
146
|
|
|
148
|
-
In the example above, the atomic
|
|
147
|
+
In the example above, the atomic function `load` makes
|
|
149
148
|
changes to `url`, `content` and `timestamp` properties.
|
|
150
|
-
While atomic
|
|
151
|
-
only inside the
|
|
152
|
-
atomically visible outside of the
|
|
149
|
+
While atomic function is running, the changes are visible
|
|
150
|
+
only inside the function itself. The new values become
|
|
151
|
+
atomically visible outside of the function only upon its
|
|
153
152
|
completion.
|
|
154
153
|
|
|
155
154
|
Atomicity is achieved by making changes in an isolated
|
|
156
155
|
data snapshot that is not visible outside of the running
|
|
157
|
-
|
|
156
|
+
function until it is fully finished and applied. Multiple
|
|
158
157
|
objects and their properties can be changed with full
|
|
159
158
|
respect to the all-or-nothing principle. To do so,
|
|
160
159
|
separate data snapshot is automatically maintained for
|
|
161
|
-
each atomic
|
|
160
|
+
each atomic function. That is a logical snapshot that does
|
|
162
161
|
not create a full copy of all the data.
|
|
163
162
|
|
|
164
163
|
Compensating rollback operations are not needed in case
|
|
165
|
-
of the atomic
|
|
166
|
-
made by the atomic
|
|
167
|
-
simply discarded. In case the atomic
|
|
164
|
+
of the atomic function failure, because all the changes
|
|
165
|
+
made by the atomic function in its logical snapshot are
|
|
166
|
+
simply discarded. In case the atomic function is
|
|
168
167
|
successfully applied, affected cached results are marked
|
|
169
168
|
as obsolete and corresponding caching functions are
|
|
170
169
|
re-executed in a proper order (but only when all the
|
|
171
170
|
data changes are fully applied).
|
|
172
171
|
|
|
173
172
|
Asynchronous operations (promises) are supported out of
|
|
174
|
-
the box during atomic
|
|
173
|
+
the box during atomic function execution. Atomic function
|
|
175
174
|
may consist of a set of asynchronous calls prolonging
|
|
176
|
-
the
|
|
175
|
+
the function until completion of all of them. An
|
|
177
176
|
asynchronous call may spawn other asynchronous calls,
|
|
178
177
|
which prolong atomic atomic execution until the whole
|
|
179
178
|
chain of asynchronous operations is fully completed.
|
|
180
179
|
|
|
181
|
-
## Reactive
|
|
180
|
+
## Reactive & Cached Functions
|
|
182
181
|
|
|
183
|
-
Reactive
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
182
|
+
Reactive function is automatically and immediately called
|
|
183
|
+
in response to changes in observable objects made by
|
|
184
|
+
atomic functions. Cached function is called on-demand to
|
|
185
|
+
renew the result if it was marked as obsolete due to
|
|
186
|
+
changes made by an atomic functions. Reactive and cached
|
|
187
|
+
functions are instrumented with hooks to seamlessly
|
|
188
|
+
subscribe to those observable objects and other cached
|
|
189
|
+
functions (dependencies), which are used during their
|
|
190
|
+
execution.
|
|
192
191
|
|
|
193
192
|
``` tsx
|
|
194
193
|
class MyView extends Component<{model: MyModel}> {
|
|
@@ -211,7 +210,7 @@ class Component<P> extends React.Component<P> {
|
|
|
211
210
|
throw new Error('render method is undefined')
|
|
212
211
|
}
|
|
213
212
|
|
|
214
|
-
@
|
|
213
|
+
@reactive // called in response to changes
|
|
215
214
|
ensureUpToDate(): void {
|
|
216
215
|
if (this.shouldComponentUpdate()) {
|
|
217
216
|
// Ask React to re-render
|
|
@@ -235,34 +234,32 @@ class Component<P> extends React.Component<P> {
|
|
|
235
234
|
}
|
|
236
235
|
```
|
|
237
236
|
|
|
238
|
-
In the example above, reactive
|
|
239
|
-
transparently subscribed to the cached
|
|
240
|
-
|
|
241
|
-
`
|
|
242
|
-
`
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
While being executed, the reactive process function
|
|
237
|
+
In the example above, reactive function `refresh` is
|
|
238
|
+
transparently subscribed to the cached function `render`.
|
|
239
|
+
In turn, cached function `render` is subscribed to the
|
|
240
|
+
properties `url` and `content` of a corresponding `MyModel`
|
|
241
|
+
object. Once `url` or `content` values are changed, the
|
|
242
|
+
cached function `render` becomes obsolete and causes the
|
|
243
|
+
reactive function `refresh` to become obsolete and
|
|
244
|
+
re-executed. While being executed, the reactive function
|
|
247
245
|
`refresh` enqueues re-rendering request to React, which
|
|
248
|
-
calls `render`
|
|
249
|
-
value.
|
|
250
|
-
|
|
251
|
-
In general case, all reactive
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
246
|
+
calls cached function `render` causing it to renew its
|
|
247
|
+
cached value.
|
|
248
|
+
|
|
249
|
+
In general case, all reactive and cached functions
|
|
250
|
+
are automatically and immediately marked as obsolete
|
|
251
|
+
when changes are made in those observable objects and
|
|
252
|
+
other cached results that were used during their
|
|
253
|
+
execution. And once marked, the functions are
|
|
256
254
|
automatically executed again, either immediately (for
|
|
257
|
-
reactive
|
|
255
|
+
reactive functions) or on-demand (for cached functions).
|
|
258
256
|
|
|
259
257
|
Reactronic takes full care of tracking dependencies
|
|
260
|
-
between all the observable objects and reactive
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
new one.
|
|
258
|
+
between all the observable objects and reactive/cached
|
|
259
|
+
functions. With Reactronic, you no longer need to create
|
|
260
|
+
data change events in one set of objects, subscribe to
|
|
261
|
+
these events in other objects, and manually maintain
|
|
262
|
+
switching from the previous object version to a new one.
|
|
266
263
|
|
|
267
264
|
## Behavior Options
|
|
268
265
|
|
|
@@ -270,20 +267,20 @@ There are multiple options to configure behavior of
|
|
|
270
267
|
transactional reactivity.
|
|
271
268
|
|
|
272
269
|
**Order** options defines order of execution for
|
|
273
|
-
reactive
|
|
270
|
+
reactive functions:
|
|
274
271
|
|
|
275
272
|
- (TBD)
|
|
276
273
|
|
|
277
|
-
**Throttling** option defines how often reactive
|
|
274
|
+
**Throttling** option defines how often reactive function
|
|
278
275
|
is executed in case of recurring changes:
|
|
279
276
|
|
|
280
277
|
- `(ms)` - minimal delay in milliseconds between executions;
|
|
281
|
-
- `-1` - execute immediately once atomic
|
|
278
|
+
- `-1` - execute immediately once atomic function is applied (synchronously);
|
|
282
279
|
- `0` - execute immediately via event loop (asynchronously with zero timeout);
|
|
283
280
|
- `>= Number.MAX_SAFE_INTEGER` - never execute (suspended reaction).
|
|
284
281
|
|
|
285
282
|
**Reentrance** option defines how to handle reentrant calls of atomic
|
|
286
|
-
|
|
283
|
+
and reactive functions:
|
|
287
284
|
|
|
288
285
|
- `preventWithError` - fail with error if there is an existing call in progress;
|
|
289
286
|
- `waitAndRestart` - wait for previous call to finish and then restart current one;
|
|
@@ -293,8 +290,8 @@ actions and reactive processes:
|
|
|
293
290
|
|
|
294
291
|
**Indicator** is an object that maintains status of running functions,
|
|
295
292
|
which it is attached to. A single indicator object can be shared between
|
|
296
|
-
multiple atomic
|
|
297
|
-
|
|
293
|
+
multiple atomic, reactive, and cached functions, thus maintaining
|
|
294
|
+
consolidated status for all of them (busy, workers, etc).
|
|
298
295
|
|
|
299
296
|
## Notes
|
|
300
297
|
|
|
@@ -331,13 +328,13 @@ class ObservableObject { }
|
|
|
331
328
|
|
|
332
329
|
function observable(proto, prop) // field only
|
|
333
330
|
function unobservable(proto, prop) // field only
|
|
334
|
-
function
|
|
335
|
-
function
|
|
336
|
-
function
|
|
331
|
+
function atomic(proto, prop, pd) // method only
|
|
332
|
+
function reactive(proto, prop, pd) // method only
|
|
333
|
+
function cached(proto, prop, pd) // method only
|
|
337
334
|
function options(value: Partial<MemberOptions>): F<any>
|
|
338
335
|
|
|
339
|
-
function
|
|
340
|
-
function
|
|
336
|
+
function nonReactiveRun<T>(func: F<T>, ...args: any[]): T
|
|
337
|
+
function sensitiveRun<T>(sensitivity: Sensitivity, func: F<T>, ...args: any[]): T
|
|
341
338
|
|
|
342
339
|
// SnapshotOptions, MemberOptions, Kind, Reentrance, Indicator, LoggingOptions, ProfilingOptions
|
|
343
340
|
|
|
@@ -364,9 +361,9 @@ type MemberOptions = {
|
|
|
364
361
|
|
|
365
362
|
enum Kind {
|
|
366
363
|
plain = 0,
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
364
|
+
atomic = 1,
|
|
365
|
+
reactive = 2,
|
|
366
|
+
cached = 3
|
|
370
367
|
}
|
|
371
368
|
|
|
372
369
|
enum Reentrance {
|
|
@@ -8,7 +8,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
import { ObservableObject } from "./core/Mvcc.js";
|
|
11
|
-
import { atomic } from "./ReactiveSystem.js";
|
|
11
|
+
import { atomic, reactive } from "./ReactiveSystem.js";
|
|
12
12
|
export class Clock extends ObservableObject {
|
|
13
13
|
constructor(interval = 1000) {
|
|
14
14
|
super();
|
|
@@ -19,7 +19,7 @@ export class Clock extends ObservableObject {
|
|
|
19
19
|
this.interval = 0;
|
|
20
20
|
this.paused = false;
|
|
21
21
|
this.interval = interval;
|
|
22
|
-
this.
|
|
22
|
+
this.put(new Date());
|
|
23
23
|
}
|
|
24
24
|
pause(value = true) {
|
|
25
25
|
this.paused = value;
|
|
@@ -28,16 +28,22 @@ export class Clock extends ObservableObject {
|
|
|
28
28
|
let calibration = 0;
|
|
29
29
|
try {
|
|
30
30
|
const now = new Date();
|
|
31
|
-
this.
|
|
32
|
-
this.minute = now.getMinutes();
|
|
33
|
-
this.second = now.getSeconds();
|
|
34
|
-
this.ms = now.getMilliseconds();
|
|
31
|
+
this.put(now);
|
|
35
32
|
calibration = now.getTime() % this.interval;
|
|
36
33
|
}
|
|
37
34
|
finally {
|
|
38
35
|
setTimeout(() => this.tick(), this.interval - calibration);
|
|
39
36
|
}
|
|
40
37
|
}
|
|
38
|
+
activate() {
|
|
39
|
+
this.tick();
|
|
40
|
+
}
|
|
41
|
+
put(time) {
|
|
42
|
+
this.hour = time.getHours();
|
|
43
|
+
this.minute = time.getMinutes();
|
|
44
|
+
this.second = time.getSeconds();
|
|
45
|
+
this.ms = time.getMilliseconds();
|
|
46
|
+
}
|
|
41
47
|
}
|
|
42
48
|
__decorate([
|
|
43
49
|
atomic,
|
|
@@ -51,3 +57,9 @@ __decorate([
|
|
|
51
57
|
__metadata("design:paramtypes", []),
|
|
52
58
|
__metadata("design:returntype", void 0)
|
|
53
59
|
], Clock.prototype, "tick", null);
|
|
60
|
+
__decorate([
|
|
61
|
+
reactive,
|
|
62
|
+
__metadata("design:type", Function),
|
|
63
|
+
__metadata("design:paramtypes", []),
|
|
64
|
+
__metadata("design:returntype", void 0)
|
|
65
|
+
], Clock.prototype, "activate", null);
|
|
@@ -25,9 +25,9 @@ export type MemberOptions = {
|
|
|
25
25
|
};
|
|
26
26
|
export declare enum Kind {
|
|
27
27
|
plain = 0,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
atomic = 1,
|
|
29
|
+
reactive = 2,
|
|
30
|
+
cached = 3
|
|
31
31
|
}
|
|
32
32
|
export declare enum Reentrance {
|
|
33
33
|
preventWithError = 1,
|
|
@@ -2,9 +2,9 @@ export { LoggingLevel } from "./Logging.js";
|
|
|
2
2
|
export var Kind;
|
|
3
3
|
(function (Kind) {
|
|
4
4
|
Kind[Kind["plain"] = 0] = "plain";
|
|
5
|
-
Kind[Kind["
|
|
6
|
-
Kind[Kind["
|
|
7
|
-
Kind[Kind["
|
|
5
|
+
Kind[Kind["atomic"] = 1] = "atomic";
|
|
6
|
+
Kind[Kind["reactive"] = 2] = "reactive";
|
|
7
|
+
Kind[Kind["cached"] = 3] = "cached";
|
|
8
8
|
})(Kind || (Kind = {}));
|
|
9
9
|
export var Reentrance;
|
|
10
10
|
(function (Reentrance) {
|
|
@@ -9,13 +9,13 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
};
|
|
10
10
|
import { ObservableObject } from "./core/Mvcc.js";
|
|
11
11
|
import { reactive } from "./ReactiveSystem.js";
|
|
12
|
-
export class
|
|
13
|
-
constructor(
|
|
12
|
+
export class ReactiveLoop extends ObservableObject {
|
|
13
|
+
constructor(reactiveFunction) {
|
|
14
14
|
super();
|
|
15
|
-
this.
|
|
15
|
+
this.reactiveFunction = reactiveFunction;
|
|
16
16
|
}
|
|
17
17
|
launch() {
|
|
18
|
-
return this.
|
|
18
|
+
return this.reactiveFunction();
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
__decorate([
|
|
@@ -23,4 +23,4 @@ __decorate([
|
|
|
23
23
|
__metadata("design:type", Function),
|
|
24
24
|
__metadata("design:paramtypes", []),
|
|
25
25
|
__metadata("design:returntype", Object)
|
|
26
|
-
],
|
|
26
|
+
], ReactiveLoop.prototype, "launch", null);
|
|
@@ -53,14 +53,14 @@ export function observable(proto, prop) {
|
|
|
53
53
|
}
|
|
54
54
|
export function atomic(proto, prop, pd) {
|
|
55
55
|
const opts = {
|
|
56
|
-
kind: Kind.
|
|
56
|
+
kind: Kind.atomic,
|
|
57
57
|
isolation: Isolation.joinToCurrentTransaction,
|
|
58
58
|
};
|
|
59
59
|
return Mvcc.decorateOperation(true, atomic, opts, proto, prop, pd);
|
|
60
60
|
}
|
|
61
61
|
export function reactive(proto, prop, pd) {
|
|
62
62
|
const opts = {
|
|
63
|
-
kind: Kind.
|
|
63
|
+
kind: Kind.reactive,
|
|
64
64
|
isolation: Isolation.joinAsNestedTransaction,
|
|
65
65
|
throttling: -1,
|
|
66
66
|
};
|
|
@@ -68,7 +68,7 @@ export function reactive(proto, prop, pd) {
|
|
|
68
68
|
}
|
|
69
69
|
export function cached(proto, prop, pd) {
|
|
70
70
|
const opts = {
|
|
71
|
-
kind: Kind.
|
|
71
|
+
kind: Kind.cached,
|
|
72
72
|
isolation: Isolation.joinToCurrentTransaction,
|
|
73
73
|
noSideEffects: true,
|
|
74
74
|
};
|
|
@@ -18,7 +18,7 @@ export { Indicator } from "./core/Indicator.js";
|
|
|
18
18
|
export { Journal } from "./core/Journal.js";
|
|
19
19
|
export { atomicRun, nonReactiveRun, sensitiveRun, contextualRun } from "./ReactiveSystem.js";
|
|
20
20
|
export { ReactiveSystem, observable, unobservable, atomic, reactive, cached, options } from "./ReactiveSystem.js";
|
|
21
|
-
export {
|
|
21
|
+
export { ReactiveLoop } from "./ReactiveLoop.js";
|
|
22
22
|
export { ReactiveNode, Mode, Priority, BaseDriver, ReactiveNodeVariable } from "./core/ReactiveNode.js";
|
|
23
23
|
export type { Script, ScriptAsync, Handler, ReactiveNodeDecl, ReactiveNodeDriver, ReactiveNodeContext } from "./core/ReactiveNode.js";
|
|
24
24
|
export { Clock } from "./Clock.js";
|
package/build/dist/source/api.js
CHANGED
|
@@ -14,6 +14,6 @@ export { Indicator } from "./core/Indicator.js";
|
|
|
14
14
|
export { Journal } from "./core/Journal.js";
|
|
15
15
|
export { atomicRun, nonReactiveRun, sensitiveRun, contextualRun } from "./ReactiveSystem.js";
|
|
16
16
|
export { ReactiveSystem, observable, unobservable, atomic, reactive, cached, options } from "./ReactiveSystem.js";
|
|
17
|
-
export {
|
|
17
|
+
export { ReactiveLoop } from "./ReactiveLoop.js";
|
|
18
18
|
export { ReactiveNode, Mode, Priority, BaseDriver, ReactiveNodeVariable } from "./core/ReactiveNode.js";
|
|
19
19
|
export { Clock } from "./Clock.js";
|
|
@@ -30,7 +30,7 @@ export declare class IndicatorImpl extends Indicator {
|
|
|
30
30
|
whenIdle(): Promise<void>;
|
|
31
31
|
enter(worker: Worker): void;
|
|
32
32
|
leave(worker: Worker): void;
|
|
33
|
-
static
|
|
33
|
+
static createImpl(hint: string, activationDelay: number, deactivationDelay: number, durationResolution: number): IndicatorImpl;
|
|
34
34
|
static enter(mon: IndicatorImpl, worker: Worker): void;
|
|
35
35
|
static leave(mon: IndicatorImpl, worker: Worker): void;
|
|
36
36
|
private static doCreate;
|
|
@@ -12,7 +12,7 @@ import { ObservableObject, Mvcc } from "./Mvcc.js";
|
|
|
12
12
|
import { Transaction } from "./Transaction.js";
|
|
13
13
|
export class Indicator extends ObservableObject {
|
|
14
14
|
static create(hint, activationDelay, deactivationDelay, durationResolution) {
|
|
15
|
-
return IndicatorImpl.
|
|
15
|
+
return IndicatorImpl.createImpl(hint, activationDelay, deactivationDelay, durationResolution);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
export class IndicatorImpl extends Indicator {
|
|
@@ -71,7 +71,7 @@ export class IndicatorImpl extends Indicator {
|
|
|
71
71
|
workers.delete(worker);
|
|
72
72
|
IndicatorImpl.deactivate(this, this.internals.deactivationDelay);
|
|
73
73
|
}
|
|
74
|
-
static
|
|
74
|
+
static createImpl(hint, activationDelay, deactivationDelay, durationResolution) {
|
|
75
75
|
return Transaction.run({ hint: "Indicator.create" }, IndicatorImpl.doCreate, hint, activationDelay, deactivationDelay, durationResolution);
|
|
76
76
|
}
|
|
77
77
|
static enter(mon, worker) {
|
|
@@ -99,7 +99,7 @@ export class OperationImpl {
|
|
|
99
99
|
const ov = ctx.lookupObjectVersion(this.ownerHandle, this.fieldKey, false);
|
|
100
100
|
const launch = this.acquireFromObjectVersion(ov, args);
|
|
101
101
|
const applied = this.ownerHandle.applied.data[this.fieldKey];
|
|
102
|
-
const isReusable = launch.options.kind !== Kind.
|
|
102
|
+
const isReusable = launch.options.kind !== Kind.atomic && launch.cause !== BOOT_CAUSE &&
|
|
103
103
|
(ctx === launch.changeset || ctx.timestamp < launch.obsoleteSince || applied.obsoleteDueTo === undefined) &&
|
|
104
104
|
(!launch.options.triggeringArgs || args === undefined ||
|
|
105
105
|
launch.args.length === args.length && launch.args.every((t, i) => t === args[i])) || ov.disposed;
|
|
@@ -175,7 +175,7 @@ export class OperationImpl {
|
|
|
175
175
|
}
|
|
176
176
|
else {
|
|
177
177
|
ror = this.peek(argsx);
|
|
178
|
-
if (ror.launch.options.kind === Kind.
|
|
178
|
+
if (ror.launch.options.kind === Kind.atomic || !ror.isReusable) {
|
|
179
179
|
ror = this.edit();
|
|
180
180
|
if (Log.isOn && Log.opt.operation)
|
|
181
181
|
Log.write("║", " o", `${ror.launch.why()}`);
|
|
@@ -251,7 +251,7 @@ class Launch extends FieldVersion {
|
|
|
251
251
|
let cause;
|
|
252
252
|
if (this.cause)
|
|
253
253
|
cause = ` ◀◀ ${this.cause}`;
|
|
254
|
-
else if (this.operation.options.kind === Kind.
|
|
254
|
+
else if (this.operation.options.kind === Kind.atomic)
|
|
255
255
|
cause = " ◀◀ operation";
|
|
256
256
|
else
|
|
257
257
|
cause = ` ◀◀ T${this.changeset.id}[${this.changeset.hint}]`;
|
|
@@ -294,7 +294,7 @@ class Launch extends FieldVersion {
|
|
|
294
294
|
changeset.id === this.lastEditorChangesetId;
|
|
295
295
|
if (!skip) {
|
|
296
296
|
const why = `${Dump.snapshot2(h, changeset, fk, observable)} ◀◀ ${outer}`;
|
|
297
|
-
const isReactive = this.options.kind === Kind.
|
|
297
|
+
const isReactive = this.options.kind === Kind.reactive;
|
|
298
298
|
this.obsoleteDueTo = why;
|
|
299
299
|
this.obsoleteSince = since;
|
|
300
300
|
if (Log.isOn && (Log.opt.obsolete || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.obsolete)))
|
|
@@ -326,14 +326,14 @@ class Launch extends FieldVersion {
|
|
|
326
326
|
const launch = this.operation.reuseOrRelaunch(false, undefined);
|
|
327
327
|
if (launch.result instanceof Promise)
|
|
328
328
|
launch.result.catch(error => {
|
|
329
|
-
if (launch.options.kind === Kind.
|
|
329
|
+
if (launch.options.kind === Kind.reactive)
|
|
330
330
|
misuse(`reactive function ${launch.hint()} failed and will not run anymore: ${error}`, error);
|
|
331
331
|
});
|
|
332
332
|
}
|
|
333
333
|
catch (e) {
|
|
334
334
|
if (!nothrow)
|
|
335
335
|
throw e;
|
|
336
|
-
else if (this.options.kind === Kind.
|
|
336
|
+
else if (this.options.kind === Kind.reactive)
|
|
337
337
|
misuse(`reactive ${this.hint()} failed and will not run anymore: ${e}`, e);
|
|
338
338
|
}
|
|
339
339
|
}
|
|
@@ -346,7 +346,7 @@ class Launch extends FieldVersion {
|
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
isNotUpToDate() {
|
|
349
|
-
return !this.error && (this.options.kind === Kind.
|
|
349
|
+
return !this.error && (this.options.kind === Kind.atomic ||
|
|
350
350
|
!this.successor || this.successor.transaction.isCanceled);
|
|
351
351
|
}
|
|
352
352
|
reenterOver(head) {
|
|
@@ -469,9 +469,9 @@ class Launch extends FieldVersion {
|
|
|
469
469
|
x.relaunchIfNotUpToDate(true, true);
|
|
470
470
|
}
|
|
471
471
|
static markUsed(observable, ov, fk, h, kind, weak) {
|
|
472
|
-
if (kind !== Kind.
|
|
472
|
+
if (kind !== Kind.atomic) {
|
|
473
473
|
const launch = Launch.current;
|
|
474
|
-
if (launch && launch.options.kind !== Kind.
|
|
474
|
+
if (launch && launch.options.kind !== Kind.atomic &&
|
|
475
475
|
launch.transaction === Transaction.current && fk !== Meta.Handle) {
|
|
476
476
|
const ctx = Changeset.current();
|
|
477
477
|
if (ctx !== ov.changeset)
|
|
@@ -568,10 +568,10 @@ class Launch extends FieldVersion {
|
|
|
568
568
|
}
|
|
569
569
|
static enqueueReactiveFunctionsToRun(reactive) {
|
|
570
570
|
const queue = Launch.queuedReactiveOperations;
|
|
571
|
-
const
|
|
571
|
+
const isKickOff = queue.length === 0;
|
|
572
572
|
for (const r of reactive)
|
|
573
573
|
queue.push(r);
|
|
574
|
-
if (
|
|
574
|
+
if (isKickOff)
|
|
575
575
|
OperationImpl.proceedWithinGivenLaunch(undefined, Launch.processQueuedReactiveOperations);
|
|
576
576
|
}
|
|
577
577
|
static migrateFieldVersion(fv, target) {
|
|
@@ -652,11 +652,11 @@ class Launch extends FieldVersion {
|
|
|
652
652
|
const rx = launch ? launch.operation : new OperationImpl(EMPTY_HANDLE, fk);
|
|
653
653
|
const opts = launch ? launch.options : OptionsImpl.INITIAL;
|
|
654
654
|
initial[fk] = launch = new Launch(Transaction.current, rx, EMPTY_OBJECT_VERSION.changeset, new OptionsImpl(getter, setter, opts, options, implicit), false);
|
|
655
|
-
if (launch.options.kind === Kind.
|
|
655
|
+
if (launch.options.kind === Kind.reactive && launch.options.throttling < Number.MAX_SAFE_INTEGER) {
|
|
656
656
|
const reactive = Meta.acquire(proto, Meta.Reactive);
|
|
657
657
|
reactive[fk] = launch;
|
|
658
658
|
}
|
|
659
|
-
else if (launch.options.kind === Kind.
|
|
659
|
+
else if (launch.options.kind === Kind.reactive && launch.options.throttling >= Number.MAX_SAFE_INTEGER) {
|
|
660
660
|
const reactive = Meta.getFrom(proto, Meta.Reactive);
|
|
661
661
|
delete reactive[fk];
|
|
662
662
|
}
|
|
@@ -32,7 +32,7 @@ export declare abstract class Transaction implements Worker {
|
|
|
32
32
|
}
|
|
33
33
|
export declare class TransactionImpl extends Transaction {
|
|
34
34
|
private static readonly none;
|
|
35
|
-
private static
|
|
35
|
+
private static gCurr;
|
|
36
36
|
private static isInspectionMode;
|
|
37
37
|
private static frameStartTime;
|
|
38
38
|
private static frameOverCounter;
|
|
@@ -47,7 +47,7 @@ export declare class TransactionImpl extends Transaction {
|
|
|
47
47
|
private resolve;
|
|
48
48
|
private reject;
|
|
49
49
|
constructor(options: SnapshotOptions | null, parent?: TransactionImpl);
|
|
50
|
-
static get
|
|
50
|
+
static get curr(): TransactionImpl;
|
|
51
51
|
get id(): number;
|
|
52
52
|
get hint(): string;
|
|
53
53
|
get options(): SnapshotOptions;
|
|
@@ -13,7 +13,7 @@ import { Isolation } from "../Options.js";
|
|
|
13
13
|
import { Meta } from "./Data.js";
|
|
14
14
|
import { Changeset, Dump, EMPTY_OBJECT_VERSION, UNDEFINED_REVISION } from "./Changeset.js";
|
|
15
15
|
export class Transaction {
|
|
16
|
-
static get current() { return TransactionImpl.
|
|
16
|
+
static get current() { return TransactionImpl.curr; }
|
|
17
17
|
whenFinished(includingParent) {
|
|
18
18
|
return __awaiter(this, void 0, void 0, function* () { });
|
|
19
19
|
}
|
|
@@ -23,12 +23,12 @@ export class Transaction {
|
|
|
23
23
|
static outside(func, ...args) { return TransactionImpl.outside(func, ...args); }
|
|
24
24
|
static isFrameOver(everyN = 1, timeLimit = 10) { return TransactionImpl.isFrameOver(everyN, timeLimit); }
|
|
25
25
|
static requestNextFrame(sleepTime = 0) { return TransactionImpl.requestNextFrame(sleepTime); }
|
|
26
|
-
static get isCanceled() { return TransactionImpl.
|
|
26
|
+
static get isCanceled() { return TransactionImpl.curr.isCanceled; }
|
|
27
27
|
}
|
|
28
28
|
export class TransactionImpl extends Transaction {
|
|
29
29
|
constructor(options, parent) {
|
|
30
30
|
super();
|
|
31
|
-
this.margin = TransactionImpl.
|
|
31
|
+
this.margin = TransactionImpl.gCurr !== undefined ? TransactionImpl.gCurr.margin + 1 : -1;
|
|
32
32
|
this.parent = parent;
|
|
33
33
|
this.changeset = new Changeset(options, parent === null || parent === void 0 ? void 0 : parent.changeset);
|
|
34
34
|
this.pending = 0;
|
|
@@ -39,7 +39,7 @@ export class TransactionImpl extends Transaction {
|
|
|
39
39
|
this.resolve = UNDEF;
|
|
40
40
|
this.reject = UNDEF;
|
|
41
41
|
}
|
|
42
|
-
static get
|
|
42
|
+
static get curr() { return TransactionImpl.gCurr; }
|
|
43
43
|
get id() { return this.changeset.id; }
|
|
44
44
|
get hint() { return this.changeset.hint; }
|
|
45
45
|
get options() { return this.changeset.options; }
|
|
@@ -54,7 +54,7 @@ export class TransactionImpl extends Transaction {
|
|
|
54
54
|
try {
|
|
55
55
|
TransactionImpl.isInspectionMode = true;
|
|
56
56
|
if (Log.isOn && Log.opt.transaction)
|
|
57
|
-
Log.write(" ", " ", `T${this.id}[${this.hint}] is being inspected by T${TransactionImpl.
|
|
57
|
+
Log.write(" ", " ", `T${this.id}[${this.hint}] is being inspected by T${TransactionImpl.gCurr.id}[${TransactionImpl.gCurr.hint}]`);
|
|
58
58
|
return this.runImpl(undefined, func, ...args);
|
|
59
59
|
}
|
|
60
60
|
finally {
|
|
@@ -118,7 +118,7 @@ export class TransactionImpl extends Transaction {
|
|
|
118
118
|
}
|
|
119
119
|
static run(options, func, ...args) {
|
|
120
120
|
const t = TransactionImpl.acquire(options);
|
|
121
|
-
const isRoot = t !== TransactionImpl.
|
|
121
|
+
const isRoot = t !== TransactionImpl.gCurr;
|
|
122
122
|
t.guard();
|
|
123
123
|
let result = t.runImpl(options === null || options === void 0 ? void 0 : options.logging, func, ...args);
|
|
124
124
|
if (isRoot) {
|
|
@@ -135,13 +135,13 @@ export class TransactionImpl extends Transaction {
|
|
|
135
135
|
return TransactionImpl.run({ isolation: Isolation.disjoinFromOuterTransaction }, func, ...args);
|
|
136
136
|
}
|
|
137
137
|
static outside(func, ...args) {
|
|
138
|
-
const outer = TransactionImpl.
|
|
138
|
+
const outer = TransactionImpl.gCurr;
|
|
139
139
|
try {
|
|
140
|
-
TransactionImpl.
|
|
140
|
+
TransactionImpl.gCurr = TransactionImpl.none;
|
|
141
141
|
return func(...args);
|
|
142
142
|
}
|
|
143
143
|
finally {
|
|
144
|
-
TransactionImpl.
|
|
144
|
+
TransactionImpl.gCurr = outer;
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
static isFrameOver(everyN = 1, timeLimit = 10) {
|
|
@@ -158,7 +158,7 @@ export class TransactionImpl extends Transaction {
|
|
|
158
158
|
}
|
|
159
159
|
static acquire(options) {
|
|
160
160
|
var _a;
|
|
161
|
-
const outer = TransactionImpl.
|
|
161
|
+
const outer = TransactionImpl.gCurr;
|
|
162
162
|
const isolation = (_a = options === null || options === void 0 ? void 0 : options.isolation) !== null && _a !== void 0 ? _a : Isolation.joinToCurrentTransaction;
|
|
163
163
|
if (outer.isFinished || outer.options.isolation === Isolation.disjoinFromOuterAndInnerTransactions)
|
|
164
164
|
return new TransactionImpl(options);
|
|
@@ -170,7 +170,7 @@ export class TransactionImpl extends Transaction {
|
|
|
170
170
|
return outer;
|
|
171
171
|
}
|
|
172
172
|
guard() {
|
|
173
|
-
if (this.sealed && TransactionImpl.
|
|
173
|
+
if (this.sealed && TransactionImpl.gCurr !== this)
|
|
174
174
|
throw misuse("cannot run transaction that is already sealed");
|
|
175
175
|
}
|
|
176
176
|
wrapToRetry(p, func, ...args) {
|
|
@@ -210,14 +210,14 @@ export class TransactionImpl extends Transaction {
|
|
|
210
210
|
}
|
|
211
211
|
runImpl(logging, func, ...args) {
|
|
212
212
|
let result;
|
|
213
|
-
const outer = TransactionImpl.
|
|
213
|
+
const outer = TransactionImpl.gCurr;
|
|
214
214
|
const p = this.parent;
|
|
215
215
|
try {
|
|
216
216
|
if (outer === TransactionImpl.none) {
|
|
217
217
|
TransactionImpl.frameStartTime = performance.now();
|
|
218
218
|
TransactionImpl.frameOverCounter = 0;
|
|
219
219
|
}
|
|
220
|
-
TransactionImpl.
|
|
220
|
+
TransactionImpl.gCurr = this;
|
|
221
221
|
this.pending++;
|
|
222
222
|
const acquired = this.changeset.acquire(outer.changeset);
|
|
223
223
|
if (acquired && p)
|
|
@@ -241,11 +241,11 @@ export class TransactionImpl extends Transaction {
|
|
|
241
241
|
const reactive = this.applyOrDiscard();
|
|
242
242
|
if (p)
|
|
243
243
|
p.runImpl(undefined, () => p.pending--);
|
|
244
|
-
TransactionImpl.
|
|
244
|
+
TransactionImpl.gCurr = outer;
|
|
245
245
|
TransactionImpl.outside(Changeset.enqueueReactiveFunctionsToRun, reactive);
|
|
246
246
|
}
|
|
247
247
|
else
|
|
248
|
-
TransactionImpl.
|
|
248
|
+
TransactionImpl.gCurr = outer;
|
|
249
249
|
}
|
|
250
250
|
return result;
|
|
251
251
|
}
|
|
@@ -457,12 +457,12 @@ export class TransactionImpl extends Transaction {
|
|
|
457
457
|
return this.promise;
|
|
458
458
|
}
|
|
459
459
|
static getCurrentChangeset() {
|
|
460
|
-
return TransactionImpl.
|
|
460
|
+
return TransactionImpl.gCurr.changeset;
|
|
461
461
|
}
|
|
462
462
|
static getEditableChangeset() {
|
|
463
463
|
if (TransactionImpl.isInspectionMode)
|
|
464
464
|
throw misuse("cannot make changes during transaction inspection");
|
|
465
|
-
return TransactionImpl.
|
|
465
|
+
return TransactionImpl.gCurr.changeset;
|
|
466
466
|
}
|
|
467
467
|
static _init() {
|
|
468
468
|
Changeset.current = TransactionImpl.getCurrentChangeset;
|
|
@@ -473,7 +473,7 @@ export class TransactionImpl extends Transaction {
|
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
475
|
TransactionImpl.none = new TransactionImpl({ hint: "<none>" });
|
|
476
|
-
TransactionImpl.
|
|
476
|
+
TransactionImpl.gCurr = TransactionImpl.none;
|
|
477
477
|
TransactionImpl.isInspectionMode = false;
|
|
478
478
|
TransactionImpl.frameStartTime = 0;
|
|
479
479
|
TransactionImpl.frameOverCounter = 0;
|
package/package.json
CHANGED