reactronic 0.22.320 → 0.22.400
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 +57 -62
- package/build/dist/source/Options.d.ts +3 -3
- package/build/dist/source/Options.js +3 -3
- package/build/dist/source/Ref.js +2 -2
- package/build/dist/source/Rx.d.ts +5 -5
- package/build/dist/source/Rx.js +10 -10
- package/build/dist/source/api.d.ts +1 -1
- package/build/dist/source/api.js +1 -1
- package/build/dist/source/impl/Changeset.d.ts +2 -2
- package/build/dist/source/impl/Changeset.js +4 -4
- package/build/dist/source/impl/Data.d.ts +1 -1
- package/build/dist/source/impl/Meta.d.ts +1 -1
- package/build/dist/source/impl/Meta.js +1 -1
- package/build/dist/source/impl/Mvcc.d.ts +1 -1
- package/build/dist/source/impl/Mvcc.js +3 -3
- package/build/dist/source/impl/Operation.d.ts +7 -7
- package/build/dist/source/impl/Operation.js +61 -61
- package/build/dist/source/impl/Transaction.js +5 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
# **Reactronic** - Transactional Reactive State Management
|
|
11
11
|
|
|
12
|
-
Reactronic is
|
|
12
|
+
Reactronic is an experimental JavaScript library that provides
|
|
13
13
|
[transactional reactive](https://blog.nezaboodka.com/post/2019/593-modern-database-should-natively-support-transactionally-reactive-programming)
|
|
14
14
|
state management in a Web application.
|
|
15
15
|
|
|
@@ -23,13 +23,13 @@ between visual components (observers) and state (observable objects).
|
|
|
23
23
|
Transactional reactivity is based on four fundamental concepts:
|
|
24
24
|
|
|
25
25
|
- **Observable Objects** - a set of objects that store data of an
|
|
26
|
-
application (state)
|
|
27
|
-
- **
|
|
28
|
-
objects in
|
|
29
|
-
- **
|
|
26
|
+
application (state);
|
|
27
|
+
- **Transactional Function** - makes changes in observable
|
|
28
|
+
objects in atomic way ("all or nothing");
|
|
29
|
+
- **Reactive Function** - is executed automatically in
|
|
30
30
|
response to changes made by a transaction;
|
|
31
|
-
- **
|
|
32
|
-
|
|
31
|
+
- **Cached Function** - its result is remembered and, if the becomes
|
|
32
|
+
obsolete, recomputed on-demand.
|
|
33
33
|
|
|
34
34
|
Demo application built with Reactronic: https://nevod.io/#/playground.
|
|
35
35
|
Source code of the demo: https://gitlab.com/nezaboodka/nevod.web.public/-/blob/master/README.md.
|
|
@@ -38,21 +38,20 @@ Quick introduction and detailed description is below.
|
|
|
38
38
|
|
|
39
39
|
## Quick Introduction
|
|
40
40
|
|
|
41
|
-
Here is an example of transactional reactive code
|
|
42
|
-
observable object, transaction and reaction:
|
|
41
|
+
Here is an example of transactional reactive code:
|
|
43
42
|
|
|
44
43
|
``` typescript
|
|
45
44
|
class Demo extends ObservableObject {
|
|
46
45
|
name: string = 'Nezaboodka Software'
|
|
47
46
|
email: string = 'contact@nezaboodka.com'
|
|
48
47
|
|
|
49
|
-
@
|
|
48
|
+
@transactional
|
|
50
49
|
saveContact(name: string, email: string): void {
|
|
51
50
|
this.name = name
|
|
52
51
|
this.email = email
|
|
53
52
|
}
|
|
54
53
|
|
|
55
|
-
@
|
|
54
|
+
@reactive
|
|
56
55
|
printContact(): void {
|
|
57
56
|
// depends on `name` and `email` and reacts to their changes
|
|
58
57
|
if (this.email.indexOf('@') >= 0)
|
|
@@ -62,11 +61,11 @@ class Demo extends ObservableObject {
|
|
|
62
61
|
}
|
|
63
62
|
```
|
|
64
63
|
|
|
65
|
-
In the example above, `printContact`
|
|
64
|
+
In the example above, `printContact` function depends on `name`
|
|
66
65
|
and `email` fields. It is executed automatically in response
|
|
67
|
-
to changes of these fields made by `saveContact`
|
|
66
|
+
to changes of these fields made by `saveContact` function.
|
|
68
67
|
|
|
69
|
-
Here is an example of
|
|
68
|
+
Here is an example of cached value (re-)computed on-demand:
|
|
70
69
|
|
|
71
70
|
``` typescript
|
|
72
71
|
class Demo extends ObservableObject {
|
|
@@ -78,7 +77,7 @@ class Demo extends ObservableObject {
|
|
|
78
77
|
return this.name + ' <' + this.email + '>'
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
@
|
|
80
|
+
@reactive
|
|
82
81
|
printContact(): void {
|
|
83
82
|
if (this.contact !== '')
|
|
84
83
|
Console.log(this.contact)
|
|
@@ -87,12 +86,12 @@ class Demo extends ObservableObject {
|
|
|
87
86
|
```
|
|
88
87
|
|
|
89
88
|
In the example above, the value of `contact` is computed from
|
|
90
|
-
source fields `name` and `email
|
|
91
|
-
cached and is reused until source fields `name`
|
|
92
|
-
changed. Once source fields changed, `contact`
|
|
93
|
-
|
|
94
|
-
`printContact`.
|
|
95
|
-
|
|
89
|
+
source fields `name` and `email` upon first use. Once computed,
|
|
90
|
+
the result is cached and is reused until source fields `name`
|
|
91
|
+
and `email` are changed. Once source fields changed, `contact`
|
|
92
|
+
value becomes obsolete, thus causing execution of depending
|
|
93
|
+
reactive function `printContact`. When `printContact` function
|
|
94
|
+
runs it reads `contact` and causes its re-computation.
|
|
96
95
|
|
|
97
96
|
## Observable Objects
|
|
98
97
|
|
|
@@ -112,17 +111,17 @@ In the example above, the class `MyModel` is based on Reactronic's
|
|
|
112
111
|
`ObservableObject` class and all its properties `url`, `content`,
|
|
113
112
|
and `timestamp` are hooked.
|
|
114
113
|
|
|
115
|
-
##
|
|
114
|
+
## Transactional Functions
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
in transactional (atomic) way. Such a function is instrumented
|
|
119
|
-
to provide transparent atomicity (by implicit context
|
|
120
|
-
and isolation).
|
|
116
|
+
Transactional function makes changes in observable objects
|
|
117
|
+
in transactional (atomic) way. Such a function is instrumented
|
|
118
|
+
with hooks to provide transparent atomicity (by implicit context
|
|
119
|
+
switching and isolation).
|
|
121
120
|
|
|
122
121
|
``` typescript
|
|
123
122
|
class MyModel extends ObservableObject {
|
|
124
123
|
// ...
|
|
125
|
-
@
|
|
124
|
+
@transactional
|
|
126
125
|
async load(url: string): Promise<void> {
|
|
127
126
|
this.url = url
|
|
128
127
|
this.content = await fetch(url)
|
|
@@ -160,16 +159,16 @@ all of them. An asynchronous call may spawn other asynchronous
|
|
|
160
159
|
calls, which prolong transaction execution until the whole chain
|
|
161
160
|
of asynchronous operations is fully completed.
|
|
162
161
|
|
|
163
|
-
##
|
|
162
|
+
## Reactive & Cached Functions
|
|
164
163
|
|
|
165
|
-
|
|
166
|
-
changes made by a transaction in observable objects.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
164
|
+
Reactive function is automatically and immediately called in
|
|
165
|
+
response to changes made by a transaction in observable objects.
|
|
166
|
+
Cached function is called on-demand to renew the value if it was
|
|
167
|
+
marked as obsolete due to changes made by a transaction.
|
|
168
|
+
Reactive and cached functions are instrumented with hooks
|
|
169
|
+
to seamlessly subscribe to those observable objects and
|
|
170
|
+
other cached functions (dependencies), which are used
|
|
171
|
+
during their execution.
|
|
173
172
|
|
|
174
173
|
``` tsx
|
|
175
174
|
class MyView extends Component<{model: MyModel}> {
|
|
@@ -192,7 +191,7 @@ class Component<P> extends React.Component<P> {
|
|
|
192
191
|
throw new Error('render method is undefined')
|
|
193
192
|
}
|
|
194
193
|
|
|
195
|
-
@
|
|
194
|
+
@reactive // called immediately in response to changes
|
|
196
195
|
ensureUpToDate(): void {
|
|
197
196
|
if (this.shouldComponentUpdate())
|
|
198
197
|
Transaction.outside(() => this.setState({})) // ask React to re-render
|
|
@@ -216,20 +215,20 @@ In the example above, reactive function `refresh` is transparently subscribed
|
|
|
216
215
|
to the cached function `render`. In turn, the `render` function is
|
|
217
216
|
subscribed to the `url` and `content` properties of a corresponding
|
|
218
217
|
`MyModel` object. Once `url` or `content` values are changed, the
|
|
219
|
-
`render` cache becomes obsolete and causes the `refresh`
|
|
218
|
+
`render` cache becomes obsolete and causes the `refresh` function to become
|
|
220
219
|
obsolete as well and re-executed. While being executed, the `refresh`
|
|
221
220
|
function enqueues re-rendering request to React, which calls
|
|
222
221
|
`render` function causing it to renew its cached value.
|
|
223
222
|
|
|
224
|
-
In general case, all
|
|
223
|
+
In general case, all reactive and cached functions are automatically and
|
|
225
224
|
immediately marked as obsolete when changes are made in those observable
|
|
226
|
-
objects and cached functions that were used during their execution.
|
|
225
|
+
objects and other cached functions that were used during their execution.
|
|
227
226
|
And once marked, the functions are automatically executed again,
|
|
228
227
|
either immediately (for @reactive functions) or on-demand
|
|
229
228
|
(for @cached functions).
|
|
230
229
|
|
|
231
230
|
Reactronic takes full care of tracking dependencies between
|
|
232
|
-
all the observable objects and
|
|
231
|
+
all the observable objects and reactive/cached functions.
|
|
233
232
|
With Reactronic, you no longer need to create data change events
|
|
234
233
|
in one set of objects, subscribe to these events in other objects,
|
|
235
234
|
and manually maintain switching from the previous object version
|
|
@@ -239,18 +238,20 @@ to a new one.
|
|
|
239
238
|
|
|
240
239
|
There are multiple options to configure behavior of transactional reactivity.
|
|
241
240
|
|
|
242
|
-
**Order** options defines order of
|
|
241
|
+
**Order** options defines order of execution for reactive functions:
|
|
243
242
|
|
|
244
243
|
- (TBD)
|
|
245
244
|
|
|
246
|
-
**Throttling** option defines how often
|
|
245
|
+
**Throttling** option defines how often reactive function is executed in case
|
|
246
|
+
of recurring changes:
|
|
247
247
|
|
|
248
|
-
- `(ms)` - minimal delay in milliseconds between
|
|
249
|
-
- `-1` - execute
|
|
250
|
-
- `0` - execute
|
|
251
|
-
- `>= Number.MAX_SAFE_INTEGER` - never execute
|
|
248
|
+
- `(ms)` - minimal delay in milliseconds between executions;
|
|
249
|
+
- `-1` - execute immediately once transaction is applied (synchronously);
|
|
250
|
+
- `0` - execute immediately via event loop (asynchronously with zero timeout);
|
|
251
|
+
- `>= Number.MAX_SAFE_INTEGER` - never execute (suspended reactive function).
|
|
252
252
|
|
|
253
|
-
**Reentrance** option defines how to handle reentrant calls of
|
|
253
|
+
**Reentrance** option defines how to handle reentrant calls of transactional
|
|
254
|
+
and reactive functions:
|
|
254
255
|
|
|
255
256
|
- `PreventWithError` - fail with error if there is an existing call in progress;
|
|
256
257
|
- `WaitAndRestart` - wait for previous call to finish and then restart current one;
|
|
@@ -258,9 +259,9 @@ There are multiple options to configure behavior of transactional reactivity.
|
|
|
258
259
|
- `CancelAndWaitPrevious` - cancel previous call in favor of recent one (but wait until canceling is completed)
|
|
259
260
|
- `RunSideBySide` - multiple simultaneous calls are allowed.
|
|
260
261
|
|
|
261
|
-
**Monitor** is an object that maintains
|
|
262
|
+
**Monitor** is an object that maintains status of running functions,
|
|
262
263
|
which it is attached to. A single monitor object can be shared between
|
|
263
|
-
multiple
|
|
264
|
+
multiple transactional, reactive, and cached functions, thus maintaining
|
|
264
265
|
consolidated status for all of them (busy, workers, etc).
|
|
265
266
|
|
|
266
267
|
## Notes
|
|
@@ -298,11 +299,11 @@ class ObservableObject { }
|
|
|
298
299
|
|
|
299
300
|
function raw(proto, prop) // field only
|
|
300
301
|
function transaction(proto, prop, pd) // method only
|
|
301
|
-
function
|
|
302
|
+
function reactive(proto, prop, pd) // method only
|
|
302
303
|
function cached(proto, prop, pd) // method only
|
|
303
304
|
function options(value: Partial<MemberOptions>): F<any>
|
|
304
305
|
|
|
305
|
-
function
|
|
306
|
+
function nonreactive<T>(func: F<T>, ...args: any[]): T
|
|
306
307
|
function sensitive<T>(sensitivity: Sensitivity, func: F<T>, ...args: any[]): T
|
|
307
308
|
|
|
308
309
|
// SnapshotOptions, MemberOptions, Kind, Reentrance, Monitor, LoggingOptions, ProfilingOptions
|
|
@@ -330,9 +331,9 @@ interface MemberOptions {
|
|
|
330
331
|
|
|
331
332
|
enum Kind {
|
|
332
333
|
Plain = 0,
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
Transactional = 1,
|
|
335
|
+
Reactive = 2,
|
|
336
|
+
Cached = 3
|
|
336
337
|
}
|
|
337
338
|
|
|
338
339
|
enum Reentrance {
|
|
@@ -344,12 +345,6 @@ enum Reentrance {
|
|
|
344
345
|
RunSideBySide = -3 // multiple simultaneous calls are allowed
|
|
345
346
|
}
|
|
346
347
|
|
|
347
|
-
enum Sensitivity {
|
|
348
|
-
ReactOnFinalDifferenceOnly = 0, // default
|
|
349
|
-
ReactOnFinalAndIntermediateDifference = 1,
|
|
350
|
-
ReactEvenOnSameValueAssignment = 2,
|
|
351
|
-
}
|
|
352
|
-
|
|
353
348
|
class Monitor {
|
|
354
349
|
readonly isActive: boolean
|
|
355
350
|
readonly counter: number
|
|
@@ -440,7 +435,7 @@ class Reactronic {
|
|
|
440
435
|
static getRevisionOf(obj: any): number
|
|
441
436
|
static takeSnapshot<T>(obj: T): T
|
|
442
437
|
static dispose(obj: any): void
|
|
443
|
-
static
|
|
438
|
+
static reactivityAutoStartDisabled: boolean
|
|
444
439
|
static readonly isLogging: boolean
|
|
445
440
|
static readonly loggingOptions: LoggingOptions
|
|
446
441
|
static setLoggingMode(isOn: boolean, options?: LoggingOptions)
|
|
@@ -2,9 +2,9 @@ export { LoggingLevel } from './Logging';
|
|
|
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["Transactional"] = 1] = "Transactional";
|
|
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) {
|
package/build/dist/source/Ref.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Transaction } from './impl/Transaction';
|
|
2
|
-
import {
|
|
2
|
+
import { nonreactive } from './Rx';
|
|
3
3
|
export class Ref {
|
|
4
4
|
constructor(owner, name, index = -1) {
|
|
5
5
|
this.owner = owner;
|
|
@@ -19,7 +19,7 @@ export class Ref {
|
|
|
19
19
|
this.owner[this.name][this.index] = value;
|
|
20
20
|
}
|
|
21
21
|
unobservable() {
|
|
22
|
-
return
|
|
22
|
+
return nonreactive(() => this.variable);
|
|
23
23
|
}
|
|
24
24
|
observe() {
|
|
25
25
|
return this.variable;
|
|
@@ -9,8 +9,8 @@ export declare class Rx {
|
|
|
9
9
|
static getRevisionOf(obj: any): number;
|
|
10
10
|
static takeSnapshot<T>(obj: T): T;
|
|
11
11
|
static dispose(obj: any): void;
|
|
12
|
-
static get
|
|
13
|
-
static set
|
|
12
|
+
static get reactivityAutoStartDisabled(): boolean;
|
|
13
|
+
static set reactivityAutoStartDisabled(value: boolean);
|
|
14
14
|
static get isLogging(): boolean;
|
|
15
15
|
static get loggingOptions(): LoggingOptions;
|
|
16
16
|
static setLoggingMode(isOn: boolean, options?: LoggingOptions): void;
|
|
@@ -18,10 +18,10 @@ export declare class Rx {
|
|
|
18
18
|
static getLoggingHint<T extends object>(obj: T, full?: boolean): string | undefined;
|
|
19
19
|
static setProfilingMode(isOn: boolean, options?: Partial<ProfilingOptions>): void;
|
|
20
20
|
}
|
|
21
|
-
export declare function
|
|
21
|
+
export declare function nonreactive<T>(func: F<T>, ...args: any[]): T;
|
|
22
22
|
export declare function sensitive<T>(sensitivity: boolean, func: F<T>, ...args: any[]): T;
|
|
23
23
|
export declare function raw(proto: object, prop: PropertyKey): any;
|
|
24
|
-
export declare function
|
|
25
|
-
export declare function
|
|
24
|
+
export declare function transactional(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
25
|
+
export declare function reactive(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
26
26
|
export declare function cached(proto: object, prop: PropertyKey, pd: PropertyDescriptor): any;
|
|
27
27
|
export declare function options(value: Partial<MemberOptions>): F<any>;
|
package/build/dist/source/Rx.js
CHANGED
|
@@ -12,8 +12,8 @@ export class Rx {
|
|
|
12
12
|
static getRevisionOf(obj) { return obj[Meta.Revision]; }
|
|
13
13
|
static takeSnapshot(obj) { return Changeset.takeSnapshot(obj); }
|
|
14
14
|
static dispose(obj) { Changeset.dispose(obj); }
|
|
15
|
-
static get
|
|
16
|
-
static set
|
|
15
|
+
static get reactivityAutoStartDisabled() { return Mvcc.reactivityAutoStartDisabled; }
|
|
16
|
+
static set reactivityAutoStartDisabled(value) { Mvcc.reactivityAutoStartDisabled = value; }
|
|
17
17
|
static get isLogging() { return Log.isOn; }
|
|
18
18
|
static get loggingOptions() { return Log.opt; }
|
|
19
19
|
static setLoggingMode(isOn, options) { Log.setMode(isOn, options); }
|
|
@@ -21,7 +21,7 @@ export class Rx {
|
|
|
21
21
|
static getLoggingHint(obj, full = false) { return ObjectHandle.getHint(obj, full); }
|
|
22
22
|
static setProfilingMode(isOn, options) { Mvcc.setProfilingMode(isOn, options); }
|
|
23
23
|
}
|
|
24
|
-
export function
|
|
24
|
+
export function nonreactive(func, ...args) {
|
|
25
25
|
return OperationController.runWithin(undefined, func, ...args);
|
|
26
26
|
}
|
|
27
27
|
export function sensitive(sensitivity, func, ...args) {
|
|
@@ -30,16 +30,16 @@ export function sensitive(sensitivity, func, ...args) {
|
|
|
30
30
|
export function raw(proto, prop) {
|
|
31
31
|
return Mvcc.decorateData(false, proto, prop);
|
|
32
32
|
}
|
|
33
|
-
export function
|
|
34
|
-
const opts = { kind: Kind.
|
|
35
|
-
return Mvcc.decorateOperation(true,
|
|
33
|
+
export function transactional(proto, prop, pd) {
|
|
34
|
+
const opts = { kind: Kind.Transactional };
|
|
35
|
+
return Mvcc.decorateOperation(true, transactional, opts, proto, prop, pd);
|
|
36
36
|
}
|
|
37
|
-
export function
|
|
38
|
-
const opts = { kind: Kind.
|
|
39
|
-
return Mvcc.decorateOperation(true,
|
|
37
|
+
export function reactive(proto, prop, pd) {
|
|
38
|
+
const opts = { kind: Kind.Reactive, throttling: -1 };
|
|
39
|
+
return Mvcc.decorateOperation(true, reactive, opts, proto, prop, pd);
|
|
40
40
|
}
|
|
41
41
|
export function cached(proto, prop, pd) {
|
|
42
|
-
const opts = { kind: Kind.
|
|
42
|
+
const opts = { kind: Kind.Cached, noSideEffects: true };
|
|
43
43
|
return Mvcc.decorateOperation(true, cached, opts, proto, prop, pd);
|
|
44
44
|
}
|
|
45
45
|
export function options(value) {
|
|
@@ -14,4 +14,4 @@ export { Changeset } from './impl/Changeset';
|
|
|
14
14
|
export { Transaction } from './impl/Transaction';
|
|
15
15
|
export { Monitor } from './impl/Monitor';
|
|
16
16
|
export { Journal } from './impl/Journal';
|
|
17
|
-
export { Rx,
|
|
17
|
+
export { Rx, raw, transactional, reactive, cached, nonreactive, sensitive, options } from './Rx';
|
package/build/dist/source/api.js
CHANGED
|
@@ -13,4 +13,4 @@ export { Changeset } from './impl/Changeset';
|
|
|
13
13
|
export { Transaction } from './impl/Transaction';
|
|
14
14
|
export { Monitor } from './impl/Monitor';
|
|
15
15
|
export { Journal } from './impl/Journal';
|
|
16
|
-
export { Rx,
|
|
16
|
+
export { Rx, raw, transactional, reactive, cached, nonreactive, sensitive, options } from './Rx';
|
|
@@ -18,7 +18,7 @@ export declare class Changeset implements AbstractChangeset {
|
|
|
18
18
|
private revision;
|
|
19
19
|
private bumper;
|
|
20
20
|
items: Map<ObjectHandle, ObjectSnapshot>;
|
|
21
|
-
|
|
21
|
+
reactive: Subscriber[];
|
|
22
22
|
sealed: boolean;
|
|
23
23
|
constructor(options: SnapshotOptions | null);
|
|
24
24
|
static current: () => Changeset;
|
|
@@ -28,7 +28,7 @@ export declare class Changeset implements AbstractChangeset {
|
|
|
28
28
|
static isConflicting: (oldValue: any, newValue: any) => boolean;
|
|
29
29
|
static propagateAllChangesThroughSubscriptions: (changeset: Changeset) => void;
|
|
30
30
|
static revokeAllSubscriptions: (changeset: Changeset) => void;
|
|
31
|
-
static
|
|
31
|
+
static enqueueReactiveFunctionsToRun: (reactive: Array<Subscriber>) => void;
|
|
32
32
|
lookupObjectSnapshot(h: ObjectHandle, m: MemberName): ObjectSnapshot;
|
|
33
33
|
getObjectSnapshot(h: ObjectHandle, m: MemberName): ObjectSnapshot;
|
|
34
34
|
getEditableObjectSnapshot(h: ObjectHandle, m: MemberName, value: any, token?: any): ObjectSnapshot;
|
|
@@ -33,7 +33,7 @@ export class Changeset {
|
|
|
33
33
|
this.revision = UNDEFINED_REVISION;
|
|
34
34
|
this.bumper = 100;
|
|
35
35
|
this.items = new Map();
|
|
36
|
-
this.
|
|
36
|
+
this.reactive = [];
|
|
37
37
|
this.sealed = false;
|
|
38
38
|
}
|
|
39
39
|
get hint() { var _a; return (_a = this.options.hint) !== null && _a !== void 0 ? _a : 'noname'; }
|
|
@@ -214,7 +214,7 @@ export class Changeset {
|
|
|
214
214
|
}
|
|
215
215
|
if (!error)
|
|
216
216
|
Changeset.propagateAllChangesThroughSubscriptions(this);
|
|
217
|
-
return this.
|
|
217
|
+
return this.reactive;
|
|
218
218
|
}
|
|
219
219
|
static sealObjectSnapshot(h, os) {
|
|
220
220
|
if (!os.disposed)
|
|
@@ -276,7 +276,7 @@ export class Changeset {
|
|
|
276
276
|
os.former.snapshot = EMPTY_SNAPSHOT;
|
|
277
277
|
});
|
|
278
278
|
this.items = EMPTY_MAP;
|
|
279
|
-
this.
|
|
279
|
+
this.reactive = EMPTY_ARRAY;
|
|
280
280
|
if (Log.isOn)
|
|
281
281
|
Object.freeze(this);
|
|
282
282
|
}
|
|
@@ -309,7 +309,7 @@ Changeset.markEdited = UNDEF;
|
|
|
309
309
|
Changeset.isConflicting = UNDEF;
|
|
310
310
|
Changeset.propagateAllChangesThroughSubscriptions = (changeset) => { };
|
|
311
311
|
Changeset.revokeAllSubscriptions = (changeset) => { };
|
|
312
|
-
Changeset.
|
|
312
|
+
Changeset.enqueueReactiveFunctionsToRun = (reactive) => { };
|
|
313
313
|
export class Dump {
|
|
314
314
|
static obj(h, m, stamp, snapshotId, originSnapshotId, value) {
|
|
315
315
|
const member = m !== undefined ? `.${m.toString()}` : '';
|
|
@@ -18,7 +18,7 @@ export interface Subscriber {
|
|
|
18
18
|
readonly subscriptions: Map<Subscription, SubscriptionInfo> | undefined;
|
|
19
19
|
readonly obsoleteSince: number;
|
|
20
20
|
hint(nop?: boolean): string;
|
|
21
|
-
markObsoleteDueTo(subscription: Subscription, m: MemberName, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number,
|
|
21
|
+
markObsoleteDueTo(subscription: Subscription, m: MemberName, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, reactive: Array<Subscriber>): void;
|
|
22
22
|
runIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
23
23
|
}
|
|
24
24
|
export declare type MemberName = PropertyKey;
|
|
@@ -3,7 +3,7 @@ export declare abstract class Meta {
|
|
|
3
3
|
static readonly Revision: unique symbol;
|
|
4
4
|
static readonly Controller: unique symbol;
|
|
5
5
|
static readonly Initial: unique symbol;
|
|
6
|
-
static readonly
|
|
6
|
+
static readonly Reactive: unique symbol;
|
|
7
7
|
static readonly Raw: unique symbol;
|
|
8
8
|
static readonly Undefined: unique symbol;
|
|
9
9
|
static get<T>(obj: any, sym: symbol): T;
|
|
@@ -24,6 +24,6 @@ Meta.Handle = Symbol('rx-handle');
|
|
|
24
24
|
Meta.Revision = Symbol('rx-revision');
|
|
25
25
|
Meta.Controller = Symbol('rx-controller');
|
|
26
26
|
Meta.Initial = Symbol('rx-initial');
|
|
27
|
-
Meta.
|
|
27
|
+
Meta.Reactive = Symbol('rx-reactive');
|
|
28
28
|
Meta.Raw = Symbol('rx-raw');
|
|
29
29
|
Meta.Undefined = Symbol('rx-undefined');
|
|
@@ -31,7 +31,7 @@ export declare class OptionsImpl implements MemberOptions {
|
|
|
31
31
|
constructor(getter: Function | undefined, setter: Function | undefined, existing: OptionsImpl, patch: Partial<OptionsImpl>, implicit: boolean);
|
|
32
32
|
}
|
|
33
33
|
export declare class Mvcc implements ProxyHandler<ObjectHandle> {
|
|
34
|
-
static
|
|
34
|
+
static reactivityAutoStartDisabled: boolean;
|
|
35
35
|
static repetitiveUsageWarningThreshold: number;
|
|
36
36
|
static mainThreadBlockingWarningThreshold: number;
|
|
37
37
|
static asyncActionDurationWarningThreshold: number;
|
|
@@ -198,8 +198,8 @@ export class Mvcc {
|
|
|
198
198
|
const mvcc = isObservable ? Mvcc.observable : Mvcc.transactional;
|
|
199
199
|
const h = new ObjectHandle(data, undefined, mvcc, EMPTY_SNAPSHOT, hint);
|
|
200
200
|
ctx.getEditableObjectSnapshot(h, Meta.Handle, blank);
|
|
201
|
-
if (!Mvcc.
|
|
202
|
-
for (const m in Meta.getFrom(proto, Meta.
|
|
201
|
+
if (!Mvcc.reactivityAutoStartDisabled)
|
|
202
|
+
for (const m in Meta.getFrom(proto, Meta.Reactive))
|
|
203
203
|
h.proxy[m][Meta.Controller].markObsolete();
|
|
204
204
|
return h;
|
|
205
205
|
}
|
|
@@ -239,7 +239,7 @@ export class Mvcc {
|
|
|
239
239
|
return h.hint;
|
|
240
240
|
}
|
|
241
241
|
}
|
|
242
|
-
Mvcc.
|
|
242
|
+
Mvcc.reactivityAutoStartDisabled = false;
|
|
243
243
|
Mvcc.repetitiveUsageWarningThreshold = Number.MAX_SAFE_INTEGER;
|
|
244
244
|
Mvcc.mainThreadBlockingWarningThreshold = Number.MAX_SAFE_INTEGER;
|
|
245
245
|
Mvcc.asyncActionDurationWarningThreshold = Number.MAX_SAFE_INTEGER;
|
|
@@ -34,8 +34,8 @@ export declare class OperationController extends Controller<any> {
|
|
|
34
34
|
}
|
|
35
35
|
declare class Operation extends Subscription implements Subscriber {
|
|
36
36
|
static current?: Operation;
|
|
37
|
-
static
|
|
38
|
-
static
|
|
37
|
+
static queuedReactiveFunctions: Array<Subscriber>;
|
|
38
|
+
static deferredReactiveFunctions: Array<Operation>;
|
|
39
39
|
readonly margin: number;
|
|
40
40
|
readonly transaction: Transaction;
|
|
41
41
|
readonly controller: OperationController;
|
|
@@ -61,7 +61,7 @@ declare class Operation extends Subscription implements Subscriber {
|
|
|
61
61
|
dependencies(): string[];
|
|
62
62
|
wrap<T>(func: F<T>): F<T>;
|
|
63
63
|
run(proxy: any, args: any[] | undefined): void;
|
|
64
|
-
markObsoleteDueTo(subscription: Subscription, m: MemberName, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number,
|
|
64
|
+
markObsoleteDueTo(subscription: Subscription, m: MemberName, changeset: AbstractChangeset, h: ObjectHandle, outer: string, since: number, reactive: Subscriber[]): void;
|
|
65
65
|
runIfNotUpToDate(now: boolean, nothrow: boolean): void;
|
|
66
66
|
isNotUpToDate(): boolean;
|
|
67
67
|
reenterOver(head: Operation): this;
|
|
@@ -71,16 +71,16 @@ declare class Operation extends Subscription implements Subscriber {
|
|
|
71
71
|
private leave;
|
|
72
72
|
private monitorEnter;
|
|
73
73
|
private monitorLeave;
|
|
74
|
-
private
|
|
75
|
-
private static
|
|
74
|
+
private addToDeferredReactiveFunctions;
|
|
75
|
+
private static processDeferredReactiveFunctions;
|
|
76
76
|
private static markUsed;
|
|
77
77
|
private static markEdited;
|
|
78
78
|
private static isConflicting;
|
|
79
79
|
private static propagateAllChangesThroughSubscriptions;
|
|
80
80
|
private static revokeAllSubscriptions;
|
|
81
81
|
private static propagateMemberChangeThroughSubscriptions;
|
|
82
|
-
private static
|
|
83
|
-
private static
|
|
82
|
+
private static enqueueReactiveFunctionsToRun;
|
|
83
|
+
private static runQueuedReactiveLoop;
|
|
84
84
|
private unsubscribeFromAllSubscriptions;
|
|
85
85
|
private subscribeTo;
|
|
86
86
|
private static canSubscribe;
|
|
@@ -36,9 +36,9 @@ export class OperationController extends Controller {
|
|
|
36
36
|
&& (!weak || op.cause === BOOT_CAUSE || !op.successor ||
|
|
37
37
|
op.successor.transaction.isFinished)) {
|
|
38
38
|
const outerOpts = (_a = Operation.current) === null || _a === void 0 ? void 0 : _a.options;
|
|
39
|
-
const separation = weak || opts.separation !== false || opts.kind === Kind.
|
|
40
|
-
(opts.kind === Kind.
|
|
41
|
-
(opts.kind === Kind.
|
|
39
|
+
const separation = weak || opts.separation !== false || opts.kind === Kind.Reactive ||
|
|
40
|
+
(opts.kind === Kind.Transactional && outerOpts && (outerOpts.noSideEffects || outerOpts.kind === Kind.Cached)) ||
|
|
41
|
+
(opts.kind === Kind.Cached && (oc.snapshot.changeset.sealed ||
|
|
42
42
|
oc.snapshot.former.snapshot !== EMPTY_SNAPSHOT));
|
|
43
43
|
const token = opts.noSideEffects ? this : undefined;
|
|
44
44
|
const oc2 = this.run(oc, separation, opts, token, args);
|
|
@@ -105,7 +105,7 @@ export class OperationController extends Controller {
|
|
|
105
105
|
const ctx = Changeset.current();
|
|
106
106
|
const os = ctx.lookupObjectSnapshot(this.objectHandle, this.memberName);
|
|
107
107
|
const op = this.acquireFromSnapshot(os, args);
|
|
108
|
-
const isValid = op.options.kind !== Kind.
|
|
108
|
+
const isValid = op.options.kind !== Kind.Transactional && op.cause !== BOOT_CAUSE &&
|
|
109
109
|
(ctx === op.changeset || ctx.timestamp < op.obsoleteSince) &&
|
|
110
110
|
(!op.options.triggeringArgs || args === undefined ||
|
|
111
111
|
op.args.length === args.length && op.args.every((t, i) => t === args[i])) || os.disposed;
|
|
@@ -181,7 +181,7 @@ export class OperationController extends Controller {
|
|
|
181
181
|
}
|
|
182
182
|
else {
|
|
183
183
|
oc = this.peek(argsx);
|
|
184
|
-
if (oc.operation.options.kind === Kind.
|
|
184
|
+
if (oc.operation.options.kind === Kind.Transactional || !oc.isUpToDate) {
|
|
185
185
|
oc = this.edit();
|
|
186
186
|
if (Log.isOn && Log.opt.operation)
|
|
187
187
|
Log.write('║', ' 𝑓', `${oc.operation.why()}`);
|
|
@@ -196,7 +196,7 @@ export class OperationController extends Controller {
|
|
|
196
196
|
static markObsolete(self) {
|
|
197
197
|
const oc = self.peek(undefined);
|
|
198
198
|
const ctx = oc.changeset;
|
|
199
|
-
oc.operation.markObsoleteDueTo(oc.operation, self.memberName, EMPTY_SNAPSHOT.changeset, EMPTY_HANDLE, BOOT_CAUSE, ctx.timestamp, ctx.
|
|
199
|
+
oc.operation.markObsoleteDueTo(oc.operation, self.memberName, EMPTY_SNAPSHOT.changeset, EMPTY_HANDLE, BOOT_CAUSE, ctx.timestamp, ctx.reactive);
|
|
200
200
|
}
|
|
201
201
|
}
|
|
202
202
|
class Operation extends Subscription {
|
|
@@ -233,7 +233,7 @@ class Operation extends Subscription {
|
|
|
233
233
|
let cause;
|
|
234
234
|
if (this.cause)
|
|
235
235
|
cause = ` << ${this.cause}`;
|
|
236
|
-
else if (this.controller.options.kind === Kind.
|
|
236
|
+
else if (this.controller.options.kind === Kind.Transactional)
|
|
237
237
|
cause = ' << operation';
|
|
238
238
|
else
|
|
239
239
|
cause = ` << T${this.changeset.id}[${this.changeset.hint}]`;
|
|
@@ -269,25 +269,25 @@ class Operation extends Subscription {
|
|
|
269
269
|
else
|
|
270
270
|
this.result = Promise.reject(this.error);
|
|
271
271
|
}
|
|
272
|
-
markObsoleteDueTo(subscription, m, changeset, h, outer, since,
|
|
272
|
+
markObsoleteDueTo(subscription, m, changeset, h, outer, since, reactive) {
|
|
273
273
|
var _a, _b, _c;
|
|
274
274
|
if (this.subscriptions !== undefined) {
|
|
275
275
|
const skip = !subscription.isOperation &&
|
|
276
276
|
changeset === this.changeset;
|
|
277
277
|
if (!skip) {
|
|
278
278
|
const why = `${Dump.snapshot2(h, changeset, m, subscription)} << ${outer}`;
|
|
279
|
-
const
|
|
279
|
+
const isReactive = this.options.kind === Kind.Reactive;
|
|
280
280
|
this.obsoleteDueTo = why;
|
|
281
281
|
this.obsoleteSince = since;
|
|
282
282
|
if (Log.isOn && (Log.opt.obsolete || ((_a = this.options.logging) === null || _a === void 0 ? void 0 : _a.obsolete)))
|
|
283
|
-
Log.write(Log.opt.transaction && !Changeset.current().sealed ? '║' : ' ',
|
|
284
|
-
? `${this.hint()} is a
|
|
285
|
-
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset, m)} since v${since}${
|
|
283
|
+
Log.write(Log.opt.transaction && !Changeset.current().sealed ? '║' : ' ', isReactive ? '█' : '▒', isReactive && changeset === EMPTY_SNAPSHOT.changeset
|
|
284
|
+
? `${this.hint()} is a reactive and will run automatically (order ${this.options.order})`
|
|
285
|
+
: `${this.hint()} is obsolete due to ${Dump.snapshot2(h, changeset, m)} since v${since}${isReactive ? ` and will run automatically (order ${this.options.order})` : ''}`);
|
|
286
286
|
this.unsubscribeFromAllSubscriptions();
|
|
287
|
-
if (
|
|
288
|
-
|
|
287
|
+
if (isReactive)
|
|
288
|
+
reactive.push(this);
|
|
289
289
|
else
|
|
290
|
-
(_b = this.subscribers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.controller.memberName, this.changeset, this.controller.objectHandle, why, since,
|
|
290
|
+
(_b = this.subscribers) === null || _b === void 0 ? void 0 : _b.forEach(s => s.markObsoleteDueTo(this, this.controller.memberName, this.changeset, this.controller.objectHandle, why, since, reactive));
|
|
291
291
|
const tran = this.transaction;
|
|
292
292
|
if (tran.changeset === changeset) {
|
|
293
293
|
}
|
|
@@ -308,15 +308,15 @@ class Operation extends Subscription {
|
|
|
308
308
|
const op = this.controller.useOrRun(false, undefined);
|
|
309
309
|
if (op.result instanceof Promise)
|
|
310
310
|
op.result.catch(error => {
|
|
311
|
-
if (op.options.kind === Kind.
|
|
312
|
-
misuse(`
|
|
311
|
+
if (op.options.kind === Kind.Reactive)
|
|
312
|
+
misuse(`reactive function ${op.hint()} failed and will not run anymore: ${error}`, error);
|
|
313
313
|
});
|
|
314
314
|
}
|
|
315
315
|
catch (e) {
|
|
316
316
|
if (!nothrow)
|
|
317
317
|
throw e;
|
|
318
|
-
else if (this.options.kind === Kind.
|
|
319
|
-
misuse(`
|
|
318
|
+
else if (this.options.kind === Kind.Reactive)
|
|
319
|
+
misuse(`reactive ${this.hint()} failed and will not run anymore: ${e}`, e);
|
|
320
320
|
}
|
|
321
321
|
}
|
|
322
322
|
}
|
|
@@ -324,11 +324,11 @@ class Operation extends Subscription {
|
|
|
324
324
|
if (hold > 0)
|
|
325
325
|
setTimeout(() => this.runIfNotUpToDate(true, true), hold);
|
|
326
326
|
else
|
|
327
|
-
this.
|
|
327
|
+
this.addToDeferredReactiveFunctions();
|
|
328
328
|
}
|
|
329
329
|
}
|
|
330
330
|
isNotUpToDate() {
|
|
331
|
-
return !this.error && (this.options.kind === Kind.
|
|
331
|
+
return !this.error && (this.options.kind === Kind.Transactional ||
|
|
332
332
|
!this.successor || this.successor.transaction.isCanceled);
|
|
333
333
|
}
|
|
334
334
|
reenterOver(head) {
|
|
@@ -437,28 +437,28 @@ class Operation extends Subscription {
|
|
|
437
437
|
this.transaction.whenFinished().then(leave, leave);
|
|
438
438
|
});
|
|
439
439
|
}
|
|
440
|
-
|
|
441
|
-
Operation.
|
|
442
|
-
if (Operation.
|
|
443
|
-
setTimeout(Operation.
|
|
440
|
+
addToDeferredReactiveFunctions() {
|
|
441
|
+
Operation.deferredReactiveFunctions.push(this);
|
|
442
|
+
if (Operation.deferredReactiveFunctions.length === 1)
|
|
443
|
+
setTimeout(Operation.processDeferredReactiveFunctions, 0);
|
|
444
444
|
}
|
|
445
|
-
static
|
|
446
|
-
const
|
|
447
|
-
Operation.
|
|
448
|
-
for (const x of
|
|
445
|
+
static processDeferredReactiveFunctions() {
|
|
446
|
+
const deferred = Operation.deferredReactiveFunctions;
|
|
447
|
+
Operation.deferredReactiveFunctions = [];
|
|
448
|
+
for (const x of deferred)
|
|
449
449
|
x.runIfNotUpToDate(true, true);
|
|
450
450
|
}
|
|
451
451
|
static markUsed(subscription, os, m, h, kind, weak) {
|
|
452
|
-
if (kind !== Kind.
|
|
452
|
+
if (kind !== Kind.Transactional) {
|
|
453
453
|
const op = Operation.current;
|
|
454
|
-
if (op && op.options.kind !== Kind.
|
|
454
|
+
if (op && op.options.kind !== Kind.Transactional &&
|
|
455
455
|
op.transaction === Transaction.current && m !== Meta.Handle) {
|
|
456
456
|
const ctx = Changeset.current();
|
|
457
457
|
if (ctx !== os.changeset)
|
|
458
458
|
ctx.bumpBy(os.changeset.timestamp);
|
|
459
459
|
const t = weak ? -1 : ctx.timestamp;
|
|
460
460
|
if (!op.subscribeTo(subscription, os, m, h, t))
|
|
461
|
-
op.markObsoleteDueTo(subscription, m, os.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.
|
|
461
|
+
op.markObsoleteDueTo(subscription, m, os.changeset, h, BOOT_CAUSE, ctx.timestamp, ctx.reactive);
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
464
|
}
|
|
@@ -476,16 +476,16 @@ class Operation extends Subscription {
|
|
|
476
476
|
static propagateAllChangesThroughSubscriptions(changeset) {
|
|
477
477
|
var _a;
|
|
478
478
|
const since = changeset.timestamp;
|
|
479
|
-
const
|
|
479
|
+
const reactive = changeset.reactive;
|
|
480
480
|
changeset.items.forEach((os, h) => {
|
|
481
|
-
Operation.propagateMemberChangeThroughSubscriptions(false, since, os, Meta.Revision, h,
|
|
481
|
+
Operation.propagateMemberChangeThroughSubscriptions(false, since, os, Meta.Revision, h, reactive);
|
|
482
482
|
if (!os.disposed)
|
|
483
|
-
os.changes.forEach((o, m) => Operation.propagateMemberChangeThroughSubscriptions(false, since, os, m, h,
|
|
483
|
+
os.changes.forEach((o, m) => Operation.propagateMemberChangeThroughSubscriptions(false, since, os, m, h, reactive));
|
|
484
484
|
else
|
|
485
485
|
for (const m in os.former.snapshot.data)
|
|
486
|
-
Operation.propagateMemberChangeThroughSubscriptions(true, since, os, m, h,
|
|
486
|
+
Operation.propagateMemberChangeThroughSubscriptions(true, since, os, m, h, reactive);
|
|
487
487
|
});
|
|
488
|
-
|
|
488
|
+
reactive.sort(compareReactiveFunctionsByOrder);
|
|
489
489
|
(_a = changeset.options.journal) === null || _a === void 0 ? void 0 : _a.edited(JournalImpl.buildPatch(changeset.hint, changeset.items));
|
|
490
490
|
}
|
|
491
491
|
static revokeAllSubscriptions(changeset) {
|
|
@@ -494,10 +494,10 @@ class Operation extends Subscription {
|
|
|
494
494
|
os.changes.forEach((o, m) => Operation.propagateMemberChangeThroughSubscriptions(true, changeset.timestamp, os, m, h, undefined));
|
|
495
495
|
});
|
|
496
496
|
}
|
|
497
|
-
static propagateMemberChangeThroughSubscriptions(unsubscribe, timestamp, os, m, h,
|
|
497
|
+
static propagateMemberChangeThroughSubscriptions(unsubscribe, timestamp, os, m, h, reactive) {
|
|
498
498
|
var _a;
|
|
499
499
|
const curr = os.data[m];
|
|
500
|
-
if (
|
|
500
|
+
if (reactive) {
|
|
501
501
|
const former = os.former.snapshot.data[m];
|
|
502
502
|
if (former !== undefined && former instanceof Subscription) {
|
|
503
503
|
const why = `T${os.changeset.id}[${os.changeset.hint}]`;
|
|
@@ -515,7 +515,7 @@ class Operation extends Subscription {
|
|
|
515
515
|
else
|
|
516
516
|
former.successor = undefined;
|
|
517
517
|
}
|
|
518
|
-
(_a = former.subscribers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former, m, os.changeset, h, why, timestamp,
|
|
518
|
+
(_a = former.subscribers) === null || _a === void 0 ? void 0 : _a.forEach(s => s.markObsoleteDueTo(former, m, os.changeset, h, why, timestamp, reactive));
|
|
519
519
|
}
|
|
520
520
|
}
|
|
521
521
|
if (curr instanceof Operation) {
|
|
@@ -533,23 +533,23 @@ class Operation extends Subscription {
|
|
|
533
533
|
else if (curr instanceof Subscription && curr.subscribers) {
|
|
534
534
|
}
|
|
535
535
|
}
|
|
536
|
-
static
|
|
537
|
-
const queue = Operation.
|
|
538
|
-
const
|
|
539
|
-
for (const r of
|
|
536
|
+
static enqueueReactiveFunctionsToRun(reactive) {
|
|
537
|
+
const queue = Operation.queuedReactiveFunctions;
|
|
538
|
+
const isReactiveLoopRequired = queue.length === 0;
|
|
539
|
+
for (const r of reactive)
|
|
540
540
|
queue.push(r);
|
|
541
|
-
if (
|
|
542
|
-
OperationController.runWithin(undefined, Operation.
|
|
541
|
+
if (isReactiveLoopRequired)
|
|
542
|
+
OperationController.runWithin(undefined, Operation.runQueuedReactiveLoop);
|
|
543
543
|
}
|
|
544
|
-
static
|
|
545
|
-
const queue = Operation.
|
|
544
|
+
static runQueuedReactiveLoop() {
|
|
545
|
+
const queue = Operation.queuedReactiveFunctions;
|
|
546
546
|
let i = 0;
|
|
547
547
|
while (i < queue.length) {
|
|
548
|
-
const
|
|
549
|
-
|
|
548
|
+
const reactive = queue[i];
|
|
549
|
+
reactive.runIfNotUpToDate(false, true);
|
|
550
550
|
i++;
|
|
551
551
|
}
|
|
552
|
-
Operation.
|
|
552
|
+
Operation.queuedReactiveFunctions = [];
|
|
553
553
|
}
|
|
554
554
|
unsubscribeFromAllSubscriptions() {
|
|
555
555
|
var _a;
|
|
@@ -608,13 +608,13 @@ class Operation extends Subscription {
|
|
|
608
608
|
const ctl = op ? op.controller : new OperationController(EMPTY_HANDLE, m);
|
|
609
609
|
const opts = op ? op.options : OptionsImpl.INITIAL;
|
|
610
610
|
initial[m] = op = new Operation(ctl, EMPTY_SNAPSHOT.changeset, new OptionsImpl(getter, setter, opts, options, implicit));
|
|
611
|
-
if (op.options.kind === Kind.
|
|
612
|
-
const
|
|
613
|
-
|
|
611
|
+
if (op.options.kind === Kind.Reactive && op.options.throttling < Number.MAX_SAFE_INTEGER) {
|
|
612
|
+
const reactive = Meta.acquire(proto, Meta.Reactive);
|
|
613
|
+
reactive[m] = op;
|
|
614
614
|
}
|
|
615
|
-
else if (op.options.kind === Kind.
|
|
616
|
-
const
|
|
617
|
-
delete
|
|
615
|
+
else if (op.options.kind === Kind.Reactive && op.options.throttling >= Number.MAX_SAFE_INTEGER) {
|
|
616
|
+
const reactive = Meta.getFrom(proto, Meta.Reactive);
|
|
617
|
+
delete reactive[m];
|
|
618
618
|
}
|
|
619
619
|
return op.options;
|
|
620
620
|
}
|
|
@@ -627,7 +627,7 @@ class Operation extends Subscription {
|
|
|
627
627
|
Changeset.isConflicting = Operation.isConflicting;
|
|
628
628
|
Changeset.propagateAllChangesThroughSubscriptions = Operation.propagateAllChangesThroughSubscriptions;
|
|
629
629
|
Changeset.revokeAllSubscriptions = Operation.revokeAllSubscriptions;
|
|
630
|
-
Changeset.
|
|
630
|
+
Changeset.enqueueReactiveFunctionsToRun = Operation.enqueueReactiveFunctionsToRun;
|
|
631
631
|
Mvcc.createOperation = Operation.createOperation;
|
|
632
632
|
Mvcc.rememberOperationOptions = Operation.rememberOperationOptions;
|
|
633
633
|
Promise.prototype.then = reactronicHookedThen;
|
|
@@ -654,8 +654,8 @@ class Operation extends Subscription {
|
|
|
654
654
|
}
|
|
655
655
|
}
|
|
656
656
|
Operation.current = undefined;
|
|
657
|
-
Operation.
|
|
658
|
-
Operation.
|
|
657
|
+
Operation.queuedReactiveFunctions = [];
|
|
658
|
+
Operation.deferredReactiveFunctions = [];
|
|
659
659
|
function valueHint(value, m) {
|
|
660
660
|
let result = '';
|
|
661
661
|
if (Array.isArray(value))
|
|
@@ -704,7 +704,7 @@ function reactronicHookedThen(resolve, reject) {
|
|
|
704
704
|
}
|
|
705
705
|
return ORIGINAL_PROMISE_THEN.call(this, resolve, reject);
|
|
706
706
|
}
|
|
707
|
-
function
|
|
707
|
+
function compareReactiveFunctionsByOrder(a, b) {
|
|
708
708
|
return a.order - b.order;
|
|
709
709
|
}
|
|
710
710
|
export function resolveReturn(value) {
|
|
@@ -224,9 +224,9 @@ class TransactionImpl extends Transaction {
|
|
|
224
224
|
finally {
|
|
225
225
|
this.pending--;
|
|
226
226
|
if (this.sealed && this.pending === 0) {
|
|
227
|
-
const
|
|
227
|
+
const reactive = this.applyOrDiscard();
|
|
228
228
|
TransactionImpl.curr = outer;
|
|
229
|
-
TransactionImpl.outside(Changeset.
|
|
229
|
+
TransactionImpl.outside(Changeset.enqueueReactiveFunctionsToRun, reactive);
|
|
230
230
|
}
|
|
231
231
|
else
|
|
232
232
|
TransactionImpl.curr = outer;
|
|
@@ -255,11 +255,11 @@ class TransactionImpl extends Transaction {
|
|
|
255
255
|
throw error(`T${this.id}[${this.hint}] conflicts with: ${Dump.conflicts(conflicts)}`, undefined);
|
|
256
256
|
}
|
|
257
257
|
applyOrDiscard() {
|
|
258
|
-
let
|
|
258
|
+
let reactive;
|
|
259
259
|
try {
|
|
260
260
|
if (Log.isOn && Log.opt.change)
|
|
261
261
|
Log.write('╠═', '', '', undefined, 'changes');
|
|
262
|
-
|
|
262
|
+
reactive = this.changeset.applyOrDiscard(this.canceled);
|
|
263
263
|
this.changeset.triggerGarbageCollection();
|
|
264
264
|
if (this.promise) {
|
|
265
265
|
if (this.canceled && !this.after)
|
|
@@ -274,7 +274,7 @@ class TransactionImpl extends Transaction {
|
|
|
274
274
|
fatal(e);
|
|
275
275
|
throw e;
|
|
276
276
|
}
|
|
277
|
-
return
|
|
277
|
+
return reactive;
|
|
278
278
|
}
|
|
279
279
|
acquirePromise() {
|
|
280
280
|
if (!this.promise) {
|