@planet-matrix/mobius-model 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/README.md +21 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +12 -6
- package/dist/reactor/index.d.ts +3 -0
- package/dist/reactor/index.d.ts.map +1 -0
- package/dist/reactor/reactor-core/flags.d.ts.map +1 -0
- package/dist/reactor/reactor-core/index.d.ts.map +1 -0
- package/dist/reactor/reactor-core/primitive.d.ts +276 -0
- package/dist/reactor/reactor-core/primitive.d.ts.map +1 -0
- package/dist/{signal/signal-core → reactor/reactor-core}/reactive-system.d.ts +102 -22
- package/dist/reactor/reactor-core/reactive-system.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/branch.d.ts +19 -0
- package/dist/reactor/reactor-operators/branch.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/convert.d.ts +30 -0
- package/dist/reactor/reactor-operators/convert.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/create.d.ts +26 -0
- package/dist/reactor/reactor-operators/create.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/filter.d.ts +269 -0
- package/dist/reactor/reactor-operators/filter.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/index.d.ts +8 -0
- package/dist/reactor/reactor-operators/index.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/join.d.ts +48 -0
- package/dist/reactor/reactor-operators/join.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/map.d.ts +165 -0
- package/dist/reactor/reactor-operators/map.d.ts.map +1 -0
- package/dist/reactor/reactor-operators/utility.d.ts +48 -0
- package/dist/reactor/reactor-operators/utility.d.ts.map +1 -0
- package/package.json +9 -9
- package/src/index.ts +1 -1
- package/src/reactor/README.md +18 -0
- package/src/reactor/index.ts +2 -0
- package/src/reactor/reactor-core/primitive.ts +1046 -0
- package/src/{signal/signal-core → reactor/reactor-core}/reactive-system.ts +392 -93
- package/src/reactor/reactor-operators/branch.ts +66 -0
- package/src/reactor/reactor-operators/convert.ts +70 -0
- package/src/reactor/reactor-operators/create.ts +66 -0
- package/src/reactor/reactor-operators/filter.ts +988 -0
- package/src/reactor/reactor-operators/index.ts +7 -0
- package/src/reactor/reactor-operators/join.ts +174 -0
- package/src/reactor/reactor-operators/map.ts +599 -0
- package/src/reactor/reactor-operators/utility.ts +102 -0
- package/tests/unit/{signal/computed.spec.ts → reactor/alien-signals-computed.spec.ts} +15 -10
- package/tests/unit/reactor/alien-signals-effect-scope.spec.ts +86 -0
- package/tests/unit/reactor/alien-signals-effect.spec.ts +395 -0
- package/tests/unit/reactor/alien-signals-topology.spec.ts +361 -0
- package/tests/unit/reactor/alien-signals-trigger.spec.ts +75 -0
- package/tests/unit/reactor/alien-signals-untrack.spec.ts +91 -0
- package/tests/unit/reactor/preact-signal.spec.ts +73 -0
- package/tests/unit/reactor/reactor-core.spec.ts +219 -0
- package/tests/unit/reactor/reactor-operators-branch.spec.ts +33 -0
- package/tests/unit/reactor/reactor-operators-convert.spec.ts +31 -0
- package/tests/unit/reactor/reactor-operators-create.spec.ts +47 -0
- package/tests/unit/reactor/reactor-operators-filter.spec.ts +604 -0
- package/tests/unit/reactor/reactor-operators-join.spec.ts +94 -0
- package/tests/unit/reactor/reactor-operators-map.spec.ts +327 -0
- package/tests/unit/reactor/reactor-operators-utility.spec.ts +55 -0
- package/dist/signal/index.d.ts +0 -3
- package/dist/signal/index.d.ts.map +0 -1
- package/dist/signal/signal-core/flags.d.ts.map +0 -1
- package/dist/signal/signal-core/index.d.ts.map +0 -1
- package/dist/signal/signal-core/primitive.d.ts +0 -67
- package/dist/signal/signal-core/primitive.d.ts.map +0 -1
- package/dist/signal/signal-core/reactive-system.d.ts.map +0 -1
- package/dist/signal/signal-operators/index.d.ts +0 -4
- package/dist/signal/signal-operators/index.d.ts.map +0 -1
- package/src/signal/index.ts +0 -2
- package/src/signal/signal-core/README.md +0 -4
- package/src/signal/signal-core/primitive.ts +0 -275
- package/src/signal/signal-operators/index.ts +0 -19
- package/tests/unit/signal/effect.spec.ts +0 -108
- /package/dist/{signal/signal-core → reactor/reactor-core}/flags.d.ts +0 -0
- /package/dist/{signal/signal-core → reactor/reactor-core}/index.d.ts +0 -0
- /package/src/{signal/signal-core → reactor/reactor-core}/flags.ts +0 -0
- /package/src/{signal/signal-core → reactor/reactor-core}/index.ts +0 -0
|
@@ -38,11 +38,11 @@ export interface Link {
|
|
|
38
38
|
*/
|
|
39
39
|
dep: Node;
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* 连接中的上游节点的下游连接链中的上一个连接。(上一个下游连接)
|
|
42
42
|
*/
|
|
43
43
|
prevSubLink?: Link | undefined;
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* 连接中的上游节点的下游连接链中的下一个连接。(下一个下游连接)
|
|
46
46
|
*/
|
|
47
47
|
nextSubLink?: Link | undefined;
|
|
48
48
|
|
|
@@ -61,6 +61,31 @@ export interface Link {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export interface CreateReactiveSystemOptions {
|
|
64
|
+
/**
|
|
65
|
+
* 当节点的上游节点发生变化时此回调会执行。
|
|
66
|
+
*/
|
|
67
|
+
onDepChanged?: (sub: Node) => void;
|
|
68
|
+
/**
|
|
69
|
+
* 当节点的下游节点发生变化时此回调会执行。
|
|
70
|
+
*/
|
|
71
|
+
onSubChanged?: (dep: Node) => void;
|
|
72
|
+
/**
|
|
73
|
+
* 当节点拥有第一个上游节点时此回调会执行。
|
|
74
|
+
*/
|
|
75
|
+
onHasDep?: (sub: Node, dep: Node) => void;
|
|
76
|
+
/**
|
|
77
|
+
* 当节点不再拥有任何上游节点时此回调会执行。
|
|
78
|
+
*/
|
|
79
|
+
onNoDep?: (sub: Node, dep: Node) => void;
|
|
80
|
+
/**
|
|
81
|
+
* 当节点拥有第一个下游节点时此回调会执行。
|
|
82
|
+
*/
|
|
83
|
+
onHasSub?: (dep: Node, sub: Node) => void;
|
|
84
|
+
/**
|
|
85
|
+
* 当节点不再拥有任何下游节点时此回调会执行。
|
|
86
|
+
*/
|
|
87
|
+
onNoSub?: (dep: Node, sub: Node) => void;
|
|
88
|
+
|
|
64
89
|
/**
|
|
65
90
|
* 当节点的值需要更新时此回调会执行,返回值表示更新前后值是否变化。
|
|
66
91
|
*/
|
|
@@ -71,12 +96,24 @@ export interface CreateReactiveSystemOptions {
|
|
|
71
96
|
* 注意:只有包含 Watching 标记的节点会触发此方法。
|
|
72
97
|
*/
|
|
73
98
|
notify(node: Node): void;
|
|
74
|
-
/**
|
|
75
|
-
* 当节点不再拥有任何下游节点时此回调会执行。
|
|
76
|
-
*/
|
|
77
|
-
unwatched(node: Node): void;
|
|
78
99
|
}
|
|
79
100
|
export interface ReactiveSystem {
|
|
101
|
+
/**
|
|
102
|
+
* 获取节点的上游连接。
|
|
103
|
+
*/
|
|
104
|
+
getDepLinksOfNode(node: Node): Link[];
|
|
105
|
+
/**
|
|
106
|
+
* 获取节点的下游连接。
|
|
107
|
+
*/
|
|
108
|
+
getSubLinksOfNode(node: Node): Link[];
|
|
109
|
+
/**
|
|
110
|
+
* 获取节点的上游节点。
|
|
111
|
+
*/
|
|
112
|
+
getDepsOfNode(node: Node): Node[];
|
|
113
|
+
/**
|
|
114
|
+
* 获取节点的下游节点。
|
|
115
|
+
*/
|
|
116
|
+
getSubsOfNode(node: Node): Node[];
|
|
80
117
|
/**
|
|
81
118
|
* 判断连接是否是节点的上游连接。
|
|
82
119
|
*/
|
|
@@ -86,34 +123,53 @@ export interface ReactiveSystem {
|
|
|
86
123
|
*/
|
|
87
124
|
isSubLinkOfNode(link: Link, node: Node): boolean;
|
|
88
125
|
/**
|
|
89
|
-
*
|
|
126
|
+
* 判断节点是否是目标节点的上游节点。
|
|
127
|
+
*/
|
|
128
|
+
isDepOfNode(node: Node, targetNode: Node): boolean;
|
|
129
|
+
/**
|
|
130
|
+
* 判断节点是否是目标节点的下游节点。
|
|
131
|
+
*/
|
|
132
|
+
isSubOfNode(node: Node, targetNode: Node): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* 获取两个节点之间的连接(从上游节点的下游连接链中查找)。
|
|
90
135
|
*/
|
|
91
|
-
|
|
136
|
+
getLinkBetweenFromDep(dep: Node, sub: Node): Link | undefined;
|
|
92
137
|
/**
|
|
93
|
-
*
|
|
138
|
+
* 获取两个节点之间的连接(从下游节点的上游连接链中查找)。
|
|
94
139
|
*/
|
|
95
|
-
|
|
140
|
+
getLinkBetweenFromSub(dep: Node, sub: Node): Link | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* 判断两个节点之间是否存在连接(从上游节点的下游连接链中查找)。
|
|
143
|
+
*/
|
|
144
|
+
hasLinkBetweenFromDep(dep: Node, sub: Node): boolean;
|
|
145
|
+
/**
|
|
146
|
+
* 判断两个节点之间是否存在连接(从下游节点的上游连接链中查找)。
|
|
147
|
+
*/
|
|
148
|
+
hasLinkBetweenFromSub(dep: Node, sub: Node): boolean;
|
|
96
149
|
/**
|
|
97
150
|
* 为两个节点建立连接。
|
|
98
151
|
*/
|
|
99
|
-
|
|
152
|
+
addLinkBetween(dep: Node, sub: Node): Link;
|
|
100
153
|
/**
|
|
101
|
-
*
|
|
154
|
+
* 为两个节点移除连接(从上游节点的下游连接链中查找)。
|
|
102
155
|
*/
|
|
103
|
-
|
|
156
|
+
removeLinkBetweenFromDep(dep: Node, sub: Node): void;
|
|
104
157
|
/**
|
|
105
|
-
*
|
|
158
|
+
* 为两个节点移除连接(从下游节点的上游连接链中查找)。
|
|
106
159
|
*/
|
|
107
|
-
|
|
160
|
+
removeLinkBetweenFromSub(dep: Node, sub: Node): void;
|
|
108
161
|
/**
|
|
109
|
-
*
|
|
162
|
+
* 移除连接。
|
|
110
163
|
*/
|
|
111
|
-
|
|
164
|
+
removeLink(link: Link): void;
|
|
112
165
|
/**
|
|
113
|
-
*
|
|
166
|
+
* 为节点移除所有上游连接。
|
|
114
167
|
*/
|
|
115
|
-
|
|
116
|
-
|
|
168
|
+
removeAllDepLinksOfNode(node: Node): Node[];
|
|
169
|
+
/**
|
|
170
|
+
* 为节点移除所有下游连接。
|
|
171
|
+
*/
|
|
172
|
+
removeAllSubLinksOfNode(node: Node): Node[];
|
|
117
173
|
|
|
118
174
|
/**
|
|
119
175
|
* 获取当前正在进行依赖收集的节点。
|
|
@@ -122,7 +178,11 @@ export interface ReactiveSystem {
|
|
|
122
178
|
/**
|
|
123
179
|
* 设置当前正在进行依赖收集的节点。
|
|
124
180
|
*/
|
|
125
|
-
setActiveNodeAsSub(nodeAsSub: Node): void;
|
|
181
|
+
setActiveNodeAsSub(nodeAsSub: Node | undefined): void;
|
|
182
|
+
/**
|
|
183
|
+
* 设置当前正在进行依赖收集的节点为空。
|
|
184
|
+
*/
|
|
185
|
+
setNoActiveNodeAsSub(): undefined;
|
|
126
186
|
/**
|
|
127
187
|
* 重置当前正在进行依赖收集的节点。
|
|
128
188
|
*/
|
|
@@ -130,7 +190,15 @@ export interface ReactiveSystem {
|
|
|
130
190
|
/**
|
|
131
191
|
* 将指定节点作为当前正在进行依赖收集的节点执行指定函数。
|
|
132
192
|
*/
|
|
133
|
-
withActiveNodeAsSub<T>(nodeAsSub: Node, fn: () => T): T;
|
|
193
|
+
withActiveNodeAsSub<T>(nodeAsSub: Node | undefined, fn: () => T): T;
|
|
194
|
+
/**
|
|
195
|
+
* 以无当前正在进行依赖收集的节点的状态执行指定函数。
|
|
196
|
+
*/
|
|
197
|
+
withoutActiveNodeAsSub<T>(fn: () => T): T;
|
|
198
|
+
/**
|
|
199
|
+
* 断言当前没有正在进行依赖收集的节点。
|
|
200
|
+
*/
|
|
201
|
+
assertWithoutActiveNodeAsSub(): void;
|
|
134
202
|
/**
|
|
135
203
|
* 开始对节点(作为下游节点)进行依赖收集。
|
|
136
204
|
*/
|
|
@@ -143,14 +211,26 @@ export interface ReactiveSystem {
|
|
|
143
211
|
* 对节点(作为下游节点)进行依赖收集。
|
|
144
212
|
*/
|
|
145
213
|
withTracking<T>(node: Node, fn: () => T): T;
|
|
214
|
+
/**
|
|
215
|
+
* 以无当前正在进行依赖收集的节点的状态执行指定函数。
|
|
216
|
+
*/
|
|
217
|
+
withoutTracking<T>(fn: () => T): T;
|
|
218
|
+
/**
|
|
219
|
+
* 断言当前没有正在进行依赖收集的节点。
|
|
220
|
+
*/
|
|
221
|
+
assertWithoutTracking(): void;
|
|
146
222
|
/**
|
|
147
223
|
* 为两个节点建立连接(依赖收集优化版)。
|
|
148
224
|
*/
|
|
149
|
-
|
|
225
|
+
addLinkBetweenOptimizedForTracking(dep: Node, sub: Node): Link;
|
|
150
226
|
/**
|
|
151
227
|
* 将节点作为当前正在进行依赖收集的节点的上游节点。
|
|
152
228
|
*/
|
|
153
229
|
track(node: Node): void;
|
|
230
|
+
/**
|
|
231
|
+
* 将节点作为当前正在进行依赖收集的节点的上游节点。
|
|
232
|
+
*/
|
|
233
|
+
trackNearestMutableOrWatching(node: Node): void;
|
|
154
234
|
|
|
155
235
|
/**
|
|
156
236
|
* 当节点的值发生变化后,调用此方法更新直接下游节点的标记。
|
|
@@ -166,60 +246,192 @@ export interface ReactiveSystem {
|
|
|
166
246
|
resolvePending(node: Node): void;
|
|
167
247
|
}
|
|
168
248
|
export const createReactiveSystem = (options: CreateReactiveSystemOptions): ReactiveSystem => {
|
|
169
|
-
const {
|
|
249
|
+
const {
|
|
250
|
+
onDepChanged,
|
|
251
|
+
onSubChanged,
|
|
252
|
+
onHasDep,
|
|
253
|
+
onNoDep,
|
|
254
|
+
onHasSub,
|
|
255
|
+
onNoSub,
|
|
256
|
+
update,
|
|
257
|
+
notify
|
|
258
|
+
} = options;
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* 获取目标节点的所有上游连接。
|
|
262
|
+
*
|
|
263
|
+
* 依赖收集过程中会尝试复用现存连接,该机制会导致在未完全完成依赖收集前,连接链中可能出现
|
|
264
|
+
* 未经验证的连接。此方法只会返回经过验证的连接。
|
|
265
|
+
*/
|
|
266
|
+
const getDepLinksOfNode = (node: Node): Link[] => {
|
|
267
|
+
const depLinks: Link[] = [];
|
|
268
|
+
let currentDepLink = node.headDepLink;
|
|
269
|
+
const tailDepLink = node.tailDepLink;
|
|
270
|
+
while (currentDepLink !== undefined) {
|
|
271
|
+
depLinks.push(currentDepLink);
|
|
272
|
+
const isValidLastDepLink = currentDepLink === tailDepLink;
|
|
273
|
+
if (isValidLastDepLink === true) {
|
|
274
|
+
break;
|
|
275
|
+
} else {
|
|
276
|
+
currentDepLink = currentDepLink.nextDepLink;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return depLinks;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* 获取目标节点的所有下游连接。
|
|
284
|
+
*
|
|
285
|
+
* 依赖收集过程中会尝试复用现存连接,该机制会导致在未完全完成依赖收集前,连接链中可能出现
|
|
286
|
+
* 未经验证的连接。此方法只会返回经过验证的连接。
|
|
287
|
+
*/
|
|
288
|
+
const getSubLinksOfNode = (node: Node): Link[] => {
|
|
289
|
+
const subLinks: Link[] = [];
|
|
290
|
+
let currentSubLink = node.headSubLink;
|
|
291
|
+
const tailSubLink = node.tailSubLink;
|
|
292
|
+
while (currentSubLink !== undefined) {
|
|
293
|
+
subLinks.push(currentSubLink);
|
|
294
|
+
const isValidLastSubLink = currentSubLink === tailSubLink;
|
|
295
|
+
if (isValidLastSubLink === true) {
|
|
296
|
+
break;
|
|
297
|
+
} else {
|
|
298
|
+
currentSubLink = currentSubLink.nextSubLink;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return subLinks;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const getDepsOfNode = (node: Node): Node[] => {
|
|
305
|
+
const depLinks = getDepLinksOfNode(node);
|
|
306
|
+
const deps = depLinks.map(link => link.dep);
|
|
307
|
+
return deps;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const getSubsOfNode = (node: Node): Node[] => {
|
|
311
|
+
const subLinks = getSubLinksOfNode(node);
|
|
312
|
+
const subs = subLinks.map(link => link.sub);
|
|
313
|
+
return subs;
|
|
314
|
+
}
|
|
170
315
|
|
|
171
316
|
const isDepLinkOfNode = (link: Link, node: Node): boolean => {
|
|
172
|
-
let
|
|
173
|
-
|
|
174
|
-
|
|
317
|
+
let currentDepLink = node.headDepLink;
|
|
318
|
+
const tailDepLink = node.tailDepLink;
|
|
319
|
+
while (currentDepLink !== undefined) {
|
|
320
|
+
if (currentDepLink === link) {
|
|
175
321
|
return true;
|
|
176
322
|
}
|
|
177
|
-
|
|
323
|
+
const isValidLastDepLink = currentDepLink === tailDepLink;
|
|
324
|
+
if (isValidLastDepLink === true) {
|
|
325
|
+
break;
|
|
326
|
+
} else {
|
|
327
|
+
currentDepLink = currentDepLink.nextDepLink;
|
|
328
|
+
}
|
|
178
329
|
}
|
|
179
330
|
return false;
|
|
180
331
|
}
|
|
181
332
|
|
|
182
333
|
const isSubLinkOfNode = (link: Link, node: Node): boolean => {
|
|
183
|
-
let
|
|
184
|
-
|
|
185
|
-
|
|
334
|
+
let currentSubLink = node.headSubLink;
|
|
335
|
+
const tailSubLink = node.tailSubLink;
|
|
336
|
+
while (currentSubLink !== undefined) {
|
|
337
|
+
if (currentSubLink === link) {
|
|
186
338
|
return true;
|
|
187
339
|
}
|
|
188
|
-
|
|
340
|
+
const isValidLastSubLink = currentSubLink === tailSubLink;
|
|
341
|
+
if (isValidLastSubLink === true) {
|
|
342
|
+
break;
|
|
343
|
+
} else {
|
|
344
|
+
currentSubLink = currentSubLink.nextSubLink;
|
|
345
|
+
}
|
|
189
346
|
}
|
|
190
347
|
return false;
|
|
191
348
|
}
|
|
192
349
|
|
|
193
|
-
const
|
|
194
|
-
let
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
350
|
+
const isDepOfNode = (node: Node, targetNode: Node): boolean => {
|
|
351
|
+
let currentDepLink = targetNode.headDepLink;
|
|
352
|
+
const tailDepLink = targetNode.tailDepLink;
|
|
353
|
+
while (currentDepLink !== undefined) {
|
|
354
|
+
if (currentDepLink.dep === node) {
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
const isValidLastDepLink = currentDepLink === tailDepLink;
|
|
358
|
+
if (isValidLastDepLink === true) {
|
|
359
|
+
break;
|
|
360
|
+
} else {
|
|
361
|
+
currentDepLink = currentDepLink.nextDepLink;
|
|
198
362
|
}
|
|
199
|
-
subToCheck = subToCheck.prevSubLink;
|
|
200
363
|
}
|
|
201
|
-
return
|
|
364
|
+
return false;
|
|
202
365
|
}
|
|
203
366
|
|
|
204
|
-
const
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
367
|
+
const isSubOfNode = (node: Node, targetNode: Node): boolean => {
|
|
368
|
+
let currentSubLink = targetNode.headSubLink;
|
|
369
|
+
const tailSubLink = targetNode.tailSubLink;
|
|
370
|
+
while (currentSubLink !== undefined) {
|
|
371
|
+
if (currentSubLink.sub === node) {
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
const isValidLastSubLink = currentSubLink === tailSubLink;
|
|
375
|
+
if (isValidLastSubLink === true) {
|
|
376
|
+
break;
|
|
377
|
+
} else {
|
|
378
|
+
currentSubLink = currentSubLink.nextSubLink;
|
|
379
|
+
}
|
|
212
380
|
}
|
|
213
381
|
return false;
|
|
214
382
|
}
|
|
215
383
|
|
|
216
|
-
const
|
|
384
|
+
const getLinkBetweenFromDep = (dep: Node, sub: Node): Link | undefined => {
|
|
385
|
+
let currentSubLink = dep.headSubLink;
|
|
386
|
+
const tailSubLink = dep.tailSubLink;
|
|
387
|
+
while (currentSubLink !== undefined) {
|
|
388
|
+
if (currentSubLink.sub === sub) {
|
|
389
|
+
return currentSubLink;
|
|
390
|
+
}
|
|
391
|
+
const isValidLastSubLink = currentSubLink === tailSubLink;
|
|
392
|
+
if (isValidLastSubLink === true) {
|
|
393
|
+
break;
|
|
394
|
+
} else {
|
|
395
|
+
currentSubLink = currentSubLink.nextSubLink;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return undefined;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const getLinkBetweenFromSub = (dep: Node, sub: Node): Link | undefined => {
|
|
402
|
+
let currentDepLink = sub.headDepLink;
|
|
403
|
+
const tailDepLink = sub.tailDepLink;
|
|
404
|
+
while (currentDepLink !== undefined) {
|
|
405
|
+
if (currentDepLink.dep === dep) {
|
|
406
|
+
return currentDepLink;
|
|
407
|
+
}
|
|
408
|
+
const isValidLastDepLink = currentDepLink === tailDepLink;
|
|
409
|
+
if (isValidLastDepLink === true) {
|
|
410
|
+
break;
|
|
411
|
+
} else {
|
|
412
|
+
currentDepLink = currentDepLink.nextDepLink;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return undefined;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
const hasLinkBetweenFromDep = (dep: Node, sub: Node): boolean => {
|
|
419
|
+
const link = getLinkBetweenFromDep(dep, sub);
|
|
420
|
+
return link !== undefined;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
const hasLinkBetweenFromSub = (dep: Node, sub: Node): boolean => {
|
|
424
|
+
const link = getLinkBetweenFromSub(dep, sub);
|
|
425
|
+
return link !== undefined;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const addLinkBetween = (dep: Node, sub: Node): Link => {
|
|
217
429
|
/**
|
|
218
430
|
* 检查是否存在重复连接。
|
|
219
431
|
*/
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
-
return;
|
|
432
|
+
const existLink = getLinkBetweenFromSub(dep, sub);
|
|
433
|
+
if (existLink !== undefined) {
|
|
434
|
+
return existLink;
|
|
223
435
|
}
|
|
224
436
|
|
|
225
437
|
/**
|
|
@@ -252,20 +464,39 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
252
464
|
dep.headSubLink = newLink;
|
|
253
465
|
}
|
|
254
466
|
dep.tailSubLink = newLink;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* 连接全部更新完成之后,触发回调,优先通知上游节点。
|
|
470
|
+
*/
|
|
471
|
+
onSubChanged?.(dep);
|
|
472
|
+
const isFirstSub = tailSubLinkOfDep === undefined;
|
|
473
|
+
if (isFirstSub === true) {
|
|
474
|
+
onHasSub?.(dep, sub);
|
|
475
|
+
}
|
|
476
|
+
onDepChanged?.(sub);
|
|
477
|
+
const isFirstDep = tailDepLinkOfSub === undefined;
|
|
478
|
+
if (isFirstDep === true) {
|
|
479
|
+
onHasDep?.(sub, dep);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return newLink;
|
|
255
483
|
}
|
|
256
484
|
|
|
257
|
-
const
|
|
258
|
-
const
|
|
259
|
-
if (
|
|
260
|
-
|
|
485
|
+
const removeLinkBetweenFromDep = (dep: Node, sub: Node): void => {
|
|
486
|
+
const linkFromDep = getLinkBetweenFromDep(dep, sub);
|
|
487
|
+
if (linkFromDep !== undefined) {
|
|
488
|
+
removeLink(linkFromDep);
|
|
261
489
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
const removeLinkBetweenFromSub = (dep: Node, sub: Node): void => {
|
|
493
|
+
const linkFromSub = getLinkBetweenFromSub(dep, sub);
|
|
494
|
+
if (linkFromSub !== undefined) {
|
|
495
|
+
removeLink(linkFromSub);
|
|
265
496
|
}
|
|
266
497
|
}
|
|
267
498
|
|
|
268
|
-
const
|
|
499
|
+
const removeLink = (link: Link): void => {
|
|
269
500
|
const prevDepLink = link.prevDepLink;
|
|
270
501
|
const dep = link.dep;
|
|
271
502
|
const nextDepLink = link.nextDepLink;
|
|
@@ -312,13 +543,15 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
312
543
|
}
|
|
313
544
|
|
|
314
545
|
/**
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
* - 如果有:什么都不做。
|
|
318
|
-
* - 如果没有:触发回调。
|
|
546
|
+
* 连接全部更新完成之后,触发回调,优先通知上游节点。
|
|
319
547
|
*/
|
|
548
|
+
onSubChanged?.(dep);
|
|
320
549
|
if (dep.headSubLink === undefined && dep.tailSubLink === undefined) {
|
|
321
|
-
|
|
550
|
+
onNoSub?.(dep, sub);
|
|
551
|
+
}
|
|
552
|
+
onDepChanged?.(sub);
|
|
553
|
+
if (sub.headDepLink === undefined && sub.tailDepLink === undefined) {
|
|
554
|
+
onNoDep?.(sub, dep);
|
|
322
555
|
}
|
|
323
556
|
|
|
324
557
|
/**
|
|
@@ -334,22 +567,28 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
334
567
|
link.nextSubLink = undefined;
|
|
335
568
|
}
|
|
336
569
|
|
|
337
|
-
const
|
|
570
|
+
const removeAllDepLinksOfNode = (node: Node): Node[] => {
|
|
571
|
+
const depNodes = [];
|
|
338
572
|
let currentDepLink = node.headDepLink;
|
|
339
573
|
while (currentDepLink !== undefined) {
|
|
574
|
+
depNodes.push(currentDepLink.dep);
|
|
340
575
|
const nextDepLink = currentDepLink.nextDepLink;
|
|
341
|
-
|
|
576
|
+
removeLink(currentDepLink);
|
|
342
577
|
currentDepLink = nextDepLink;
|
|
343
578
|
}
|
|
579
|
+
return depNodes;
|
|
344
580
|
}
|
|
345
581
|
|
|
346
|
-
const
|
|
582
|
+
const removeAllSubLinksOfNode = (node: Node): Node[] => {
|
|
583
|
+
const subNodes = [];
|
|
347
584
|
let currentSubLink = node.headSubLink;
|
|
348
585
|
while (currentSubLink !== undefined) {
|
|
586
|
+
subNodes.push(currentSubLink.sub);
|
|
349
587
|
const nextSubLink = currentSubLink.nextSubLink;
|
|
350
|
-
|
|
588
|
+
removeLink(currentSubLink);
|
|
351
589
|
currentSubLink = nextSubLink;
|
|
352
590
|
}
|
|
591
|
+
return subNodes;
|
|
353
592
|
}
|
|
354
593
|
|
|
355
594
|
let prevActiveNodeAsSubStack: Array<Node | undefined> = [];
|
|
@@ -357,14 +596,20 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
357
596
|
const getActiveNodeAsSub = (): Node | undefined => {
|
|
358
597
|
return activeNodeAsSub;
|
|
359
598
|
}
|
|
360
|
-
const setActiveNodeAsSub = (nodeAsSub: Node):
|
|
599
|
+
const setActiveNodeAsSub = (nodeAsSub: Node | undefined): Node | undefined => {
|
|
361
600
|
prevActiveNodeAsSubStack.push(activeNodeAsSub);
|
|
362
601
|
activeNodeAsSub = nodeAsSub;
|
|
602
|
+
return activeNodeAsSub;
|
|
363
603
|
}
|
|
364
|
-
const
|
|
604
|
+
const setNoActiveNodeAsSub = (): undefined => {
|
|
605
|
+
// oxlint-disable-next-line no-unsafe-type-assertion
|
|
606
|
+
return setActiveNodeAsSub(undefined) as undefined;
|
|
607
|
+
}
|
|
608
|
+
const resetActiveNodeAsSub = (): Node | undefined => {
|
|
365
609
|
activeNodeAsSub = prevActiveNodeAsSubStack.pop();
|
|
610
|
+
return activeNodeAsSub;
|
|
366
611
|
}
|
|
367
|
-
const withActiveNodeAsSub = <T>(nodeAsSub: Node, fn: () => T): T => {
|
|
612
|
+
const withActiveNodeAsSub = <T>(nodeAsSub: Node | undefined, fn: () => T): T => {
|
|
368
613
|
setActiveNodeAsSub(nodeAsSub);
|
|
369
614
|
try {
|
|
370
615
|
return fn();
|
|
@@ -372,6 +617,15 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
372
617
|
resetActiveNodeAsSub();
|
|
373
618
|
}
|
|
374
619
|
}
|
|
620
|
+
const withoutActiveNodeAsSub = <T>(fn: () => T): T => {
|
|
621
|
+
return withActiveNodeAsSub(undefined, fn);
|
|
622
|
+
}
|
|
623
|
+
const assertWithoutActiveNodeAsSub = (): void => {
|
|
624
|
+
const currentActiveNodeAsSub = getActiveNodeAsSub();
|
|
625
|
+
if (currentActiveNodeAsSub !== undefined) {
|
|
626
|
+
throw new Error(`Expected no active node as sub, but got one.`);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
375
629
|
|
|
376
630
|
const startTracking = (nodeAsSub: Node): void => {
|
|
377
631
|
setActiveNodeAsSub(nodeAsSub);
|
|
@@ -387,7 +641,7 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
387
641
|
let toRemove: Link | undefined = firstRedundantDepLink;
|
|
388
642
|
while (toRemove !== undefined) {
|
|
389
643
|
const nextToRemove: Link | undefined = toRemove.nextDepLink;
|
|
390
|
-
|
|
644
|
+
removeLink(toRemove);
|
|
391
645
|
toRemove = nextToRemove;
|
|
392
646
|
}
|
|
393
647
|
}
|
|
@@ -404,18 +658,30 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
404
658
|
endTracking(node);
|
|
405
659
|
}
|
|
406
660
|
}
|
|
661
|
+
const withoutTracking = <T>(fn: () => T): T => {
|
|
662
|
+
return withoutActiveNodeAsSub(() => {
|
|
663
|
+
return fn();
|
|
664
|
+
});
|
|
665
|
+
}
|
|
666
|
+
const assertWithoutTracking = (): void => {
|
|
667
|
+
try {
|
|
668
|
+
assertWithoutActiveNodeAsSub();
|
|
669
|
+
} catch {
|
|
670
|
+
throw new Error(`Expected no active node as sub for tracking, but got one.`);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
407
673
|
/**
|
|
408
674
|
* 依赖收集的目标是:在完成一次依赖收集之后,对于所有在依赖收集执行过程中被访问过的节点(上游节点),
|
|
409
675
|
* 都与进行依赖收集的节点(下游节点)建立且仅建立一个连接。
|
|
410
676
|
*/
|
|
411
|
-
const
|
|
677
|
+
const addLinkBetweenOptimizedForTracking = (dep: Node, sub: Node): Link => {
|
|
412
678
|
let existingDepLinkToCompare: Link | undefined;
|
|
413
679
|
|
|
414
680
|
const subFlags = sub.flags;
|
|
415
681
|
if (subFlags.hasTracking() === true && subFlags.hasTrackingReusing() === false) {
|
|
416
682
|
subFlags.setTrackingReusing();
|
|
417
683
|
sub.tailDepLink = sub.headDepLink;
|
|
418
|
-
existingDepLinkToCompare = sub.tailDepLink
|
|
684
|
+
existingDepLinkToCompare = sub.tailDepLink;
|
|
419
685
|
} else {
|
|
420
686
|
existingDepLinkToCompare = sub.tailDepLink?.nextDepLink;
|
|
421
687
|
}
|
|
@@ -423,16 +689,34 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
423
689
|
/**
|
|
424
690
|
* 检查是否可以复用现存连接。
|
|
425
691
|
*/
|
|
692
|
+
|
|
426
693
|
if (existingDepLinkToCompare !== undefined && existingDepLinkToCompare.dep === dep) {
|
|
427
|
-
|
|
694
|
+
// 如果可以,则复用该连接
|
|
695
|
+
sub.tailDepLink = existingDepLinkToCompare;
|
|
696
|
+
// 触发回调
|
|
697
|
+
onDepChanged?.(sub);
|
|
698
|
+
return existingDepLinkToCompare;
|
|
699
|
+
} else {
|
|
700
|
+
// 否则,建立新连接
|
|
701
|
+
const newLink = addLinkBetween(dep, sub);
|
|
702
|
+
return newLink;
|
|
428
703
|
}
|
|
429
|
-
|
|
430
|
-
linkNode(dep, sub);
|
|
431
704
|
}
|
|
432
705
|
const track = (node: Node): void => {
|
|
433
|
-
|
|
434
|
-
if (
|
|
435
|
-
|
|
706
|
+
let targetSub = getActiveNodeAsSub();
|
|
707
|
+
if (targetSub !== undefined) {
|
|
708
|
+
addLinkBetweenOptimizedForTracking(node, targetSub);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
const trackNearestMutableOrWatching = (node: Node): void => {
|
|
712
|
+
let targetSub = getActiveNodeAsSub();
|
|
713
|
+
while (targetSub !== undefined) {
|
|
714
|
+
const flags = targetSub.flags;
|
|
715
|
+
if (flags.hasMutable() === true || flags.hasWatching() === true) {
|
|
716
|
+
addLinkBetweenOptimizedForTracking(node, targetSub);
|
|
717
|
+
break;
|
|
718
|
+
}
|
|
719
|
+
targetSub = targetSub.headSubLink?.sub;
|
|
436
720
|
}
|
|
437
721
|
}
|
|
438
722
|
|
|
@@ -496,8 +780,8 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
496
780
|
* 此时,添加 Pending 标记,根据其它标记决定是否需要 Notify,根据其它标记决定是否需要 Downward。
|
|
497
781
|
*/
|
|
498
782
|
flags.setPending();
|
|
499
|
-
|
|
500
|
-
|
|
783
|
+
shouldNotify = shouldNotify;
|
|
784
|
+
shouldDownward = shouldDownward;
|
|
501
785
|
} else if (flags.hasTracking() === false) {
|
|
502
786
|
/**
|
|
503
787
|
* 进入此分支的 flags:
|
|
@@ -508,7 +792,7 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
508
792
|
*
|
|
509
793
|
* 此时,什么都不做,不需要修改标记,不需要 Notify,不需要 Downward。
|
|
510
794
|
*/
|
|
511
|
-
|
|
795
|
+
flags = flags;
|
|
512
796
|
shouldNotify = false;
|
|
513
797
|
shouldDownward = false;
|
|
514
798
|
} else if (flags.hasDirty() === false && flags.hasPending() === false) {
|
|
@@ -523,7 +807,7 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
523
807
|
*/
|
|
524
808
|
flags.setPending();
|
|
525
809
|
shouldNotify = false;
|
|
526
|
-
|
|
810
|
+
shouldDownward = shouldDownward;
|
|
527
811
|
} else {
|
|
528
812
|
/**
|
|
529
813
|
* 进入此分支的 flags:
|
|
@@ -534,7 +818,7 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
534
818
|
*
|
|
535
819
|
* 此时,不需要修改标记,不需要 Notify,不需要 Downward。
|
|
536
820
|
*/
|
|
537
|
-
|
|
821
|
+
flags = flags;
|
|
538
822
|
shouldNotify = false;
|
|
539
823
|
shouldDownward = false;
|
|
540
824
|
}
|
|
@@ -631,25 +915,40 @@ export const createReactiveSystem = (options: CreateReactiveSystemOptions): Reac
|
|
|
631
915
|
}
|
|
632
916
|
|
|
633
917
|
return {
|
|
918
|
+
getDepLinksOfNode,
|
|
919
|
+
getSubLinksOfNode,
|
|
920
|
+
getDepsOfNode,
|
|
921
|
+
getSubsOfNode,
|
|
634
922
|
isDepLinkOfNode,
|
|
635
923
|
isSubLinkOfNode,
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
924
|
+
isDepOfNode,
|
|
925
|
+
isSubOfNode,
|
|
926
|
+
getLinkBetweenFromDep,
|
|
927
|
+
getLinkBetweenFromSub,
|
|
928
|
+
hasLinkBetweenFromDep,
|
|
929
|
+
hasLinkBetweenFromSub,
|
|
930
|
+
addLinkBetween,
|
|
931
|
+
removeLinkBetweenFromDep,
|
|
932
|
+
removeLinkBetweenFromSub,
|
|
933
|
+
removeLink,
|
|
934
|
+
removeAllDepLinksOfNode,
|
|
935
|
+
removeAllSubLinksOfNode,
|
|
643
936
|
|
|
644
937
|
getActiveNodeAsSub,
|
|
645
938
|
setActiveNodeAsSub,
|
|
939
|
+
setNoActiveNodeAsSub,
|
|
646
940
|
resetActiveNodeAsSub,
|
|
647
941
|
withActiveNodeAsSub,
|
|
942
|
+
withoutActiveNodeAsSub,
|
|
943
|
+
assertWithoutActiveNodeAsSub,
|
|
648
944
|
startTracking,
|
|
649
945
|
endTracking,
|
|
650
946
|
withTracking,
|
|
651
|
-
|
|
947
|
+
withoutTracking,
|
|
948
|
+
assertWithoutTracking,
|
|
949
|
+
addLinkBetweenOptimizedForTracking,
|
|
652
950
|
track,
|
|
951
|
+
trackNearestMutableOrWatching,
|
|
653
952
|
|
|
654
953
|
shallowPropagate,
|
|
655
954
|
deeeeepPropagate,
|