aoye 0.0.1 → 0.0.2
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 +40 -76
- package/dist/aoye.cjs.js +854 -696
- package/dist/aoye.esm.js +854 -697
- package/dist/aoye.umd.js +491 -331
- package/dist/shared/event.d.ts +72 -0
- package/dist/signal/src/global.d.ts +4 -0
- package/dist/signal/src/index.d.ts +1 -0
- package/dist/signal/src/schedule.d.ts +1 -1
- package/dist/signal/src/scope.d.ts +3 -1
- package/dist/signal/src/util.d.ts +2 -0
- package/package.json +2 -2
package/dist/aoye.cjs.js
CHANGED
|
@@ -2,61 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
push: Queue_$$$_push,
|
|
9
|
-
shift: Queue_$$$_shift,
|
|
10
|
-
get first() {
|
|
11
|
-
var _a;
|
|
12
|
-
return (_a = this._first) === null || _a === void 0 ? void 0 : _a.v;
|
|
13
|
-
},
|
|
14
|
-
get last() {
|
|
15
|
-
var _a;
|
|
16
|
-
return (_a = this._last) === null || _a === void 0 ? void 0 : _a.v;
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
function Queue_$$$_push(it) {
|
|
21
|
-
this.len++;
|
|
22
|
-
const {
|
|
23
|
-
_last: last
|
|
24
|
-
} = this;
|
|
25
|
-
const item = {
|
|
26
|
-
v: it
|
|
27
|
-
};
|
|
28
|
-
if (!last) {
|
|
29
|
-
this._first = this._last = item;
|
|
30
|
-
return;
|
|
5
|
+
class SortMap {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.data = {};
|
|
31
8
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
first.next = undefined;
|
|
46
|
-
if (next) {
|
|
47
|
-
next.prev = undefined;
|
|
48
|
-
} else {
|
|
49
|
-
this._last = undefined;
|
|
9
|
+
clear() {
|
|
10
|
+
this.data = {};
|
|
11
|
+
}
|
|
12
|
+
add(key, value) {
|
|
13
|
+
const {
|
|
14
|
+
data
|
|
15
|
+
} = this;
|
|
16
|
+
let list = data[key];
|
|
17
|
+
if (!list) {
|
|
18
|
+
list = [];
|
|
19
|
+
data[key] = list;
|
|
20
|
+
}
|
|
21
|
+
list.push(value);
|
|
50
22
|
}
|
|
51
|
-
this._first = next;
|
|
52
|
-
return first.v;
|
|
53
|
-
}
|
|
54
|
-
function SortMap() {
|
|
55
|
-
return {
|
|
56
|
-
data: {},
|
|
57
|
-
clear: SortMap_$$$_clear,
|
|
58
|
-
add: SortMap_$$$_add
|
|
59
|
-
};
|
|
60
23
|
}
|
|
61
24
|
// const queue = new Queue([1,2,3,4]);
|
|
62
25
|
// queue.shift()
|
|
@@ -73,21 +36,157 @@ function SortMap() {
|
|
|
73
36
|
// queue.pop()
|
|
74
37
|
// queue.push(10)
|
|
75
38
|
// queue.array();
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
function
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
39
|
+
|
|
40
|
+
const timestamp = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
|
41
|
+
var EventMode;
|
|
42
|
+
(function (EventMode) {
|
|
43
|
+
EventMode[EventMode["Immediate"] = 0] = "Immediate";
|
|
44
|
+
EventMode[EventMode["Queue"] = 1] = "Queue";
|
|
45
|
+
})(EventMode || (EventMode = {}));
|
|
46
|
+
var ProcessStatus;
|
|
47
|
+
(function (ProcessStatus) {
|
|
48
|
+
ProcessStatus[ProcessStatus["None"] = 0] = "None";
|
|
49
|
+
ProcessStatus[ProcessStatus["Processing"] = 1] = "Processing";
|
|
50
|
+
ProcessStatus[ProcessStatus["Paused"] = 2] = "Paused";
|
|
51
|
+
})(ProcessStatus || (ProcessStatus = {}));
|
|
52
|
+
const DefaultEventOpt = {
|
|
53
|
+
mode: EventMode.Immediate
|
|
54
|
+
};
|
|
55
|
+
const ALL = '__ALL_KEY';
|
|
56
|
+
class BaseEvent {
|
|
57
|
+
constructor(opt = {}) {
|
|
58
|
+
this.opt = opt;
|
|
59
|
+
this.eventQueue = [];
|
|
60
|
+
this.status = ProcessStatus.None;
|
|
61
|
+
this.subMap = new Map();
|
|
62
|
+
this.on = (type, fn) => {
|
|
63
|
+
if (type == null) type = ALL;
|
|
64
|
+
const suber = this.subMap.get(type) || new Set();
|
|
65
|
+
suber.add(fn);
|
|
66
|
+
this.subMap.set(type, suber);
|
|
67
|
+
};
|
|
68
|
+
this.off = (type, fn) => {
|
|
69
|
+
const suber = this.subMap.get(type !== null && type !== void 0 ? type : ALL);
|
|
70
|
+
if (!suber) return;
|
|
71
|
+
suber.delete(fn);
|
|
72
|
+
};
|
|
73
|
+
this.once = (type, fn) => {
|
|
74
|
+
fn['once'] = true;
|
|
75
|
+
this.on(type, fn);
|
|
76
|
+
};
|
|
77
|
+
this.promiseOnce = type => {
|
|
78
|
+
return new Promise(resolve => {
|
|
79
|
+
this.once(type, (...args) => {
|
|
80
|
+
resolve(args);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
this.setScheduler = (type, scheduler) => {
|
|
85
|
+
if (typeof type !== 'string') {
|
|
86
|
+
this.scheduler = type;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const set = this.subMap.get(type) || new Set();
|
|
90
|
+
set['scheduler'] = scheduler;
|
|
91
|
+
this.subMap.set(type, set);
|
|
92
|
+
};
|
|
93
|
+
// construct 会初始化为下面其中一种
|
|
94
|
+
this.emit = (type, ...args) => {
|
|
95
|
+
this.opt.mode === EventMode.Immediate ? this.emitImmediate(type, ...args) : this.emitQueue(type, ...args);
|
|
96
|
+
};
|
|
97
|
+
this.pause = () => this.status = ProcessStatus.Paused;
|
|
98
|
+
this.unPause = () => this.status = ProcessStatus.None;
|
|
99
|
+
this.start = () => {
|
|
100
|
+
this.status = ProcessStatus.None;
|
|
101
|
+
this.processQueue();
|
|
102
|
+
};
|
|
103
|
+
this.process = () => {
|
|
104
|
+
if (this.scheduler) {
|
|
105
|
+
return this.scheduler(this.recallScheduler);
|
|
106
|
+
}
|
|
107
|
+
return this.processQueue();
|
|
108
|
+
};
|
|
109
|
+
this.recallScheduler = () => {
|
|
110
|
+
this.scheduler(this.recallScheduler);
|
|
111
|
+
};
|
|
112
|
+
this.processQueue = () => {
|
|
113
|
+
// 如果是挂起状态则直接结束
|
|
114
|
+
if (this.status === ProcessStatus.Paused) return;
|
|
115
|
+
this.status = ProcessStatus.Processing;
|
|
116
|
+
let {
|
|
117
|
+
type,
|
|
118
|
+
args
|
|
119
|
+
} = this.eventQueue.shift() || {};
|
|
120
|
+
if (type) {
|
|
121
|
+
// 在此过程中用户可通过 pause 和 start 同步控制事件处理
|
|
122
|
+
const fns = this.subMap.get(type);
|
|
123
|
+
const allSub = this.subMap.get(ALL);
|
|
124
|
+
fns === null || fns === void 0 ? void 0 : fns.forEach(it => this.callSub(it, fns, args));
|
|
125
|
+
allSub === null || allSub === void 0 ? void 0 : allSub.forEach(it => this.callSub(it, allSub, args));
|
|
126
|
+
if (this.eventQueue.length > 0) {
|
|
127
|
+
this.processQueue();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
//@ts-ignore 队列全部处理完成,如果执行过程中被 pause
|
|
131
|
+
if (this.status !== ProcessStatus.Paused) {
|
|
132
|
+
this.status = ProcessStatus.None;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
this.dispatchEvent = iList => {
|
|
136
|
+
// 从大到小排序
|
|
137
|
+
iList.sort((a, b) => b - a);
|
|
138
|
+
iList.forEach(idx => {
|
|
139
|
+
const [item] = this.eventQueue.splice(idx, 1);
|
|
140
|
+
const {
|
|
141
|
+
type,
|
|
142
|
+
args
|
|
143
|
+
} = item || {};
|
|
144
|
+
if (type && args) {
|
|
145
|
+
this.emitImmediate(type, ...args);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
};
|
|
149
|
+
this.clear = () => {
|
|
150
|
+
this.subMap.clear();
|
|
151
|
+
this.eventQueue = [];
|
|
152
|
+
this.scheduler = undefined;
|
|
153
|
+
};
|
|
154
|
+
this.opt = {
|
|
155
|
+
...DefaultEventOpt,
|
|
156
|
+
...opt
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
callSub(it, fns, args) {
|
|
160
|
+
const doCall = (...args) => {
|
|
161
|
+
it(...args);
|
|
162
|
+
if (it['once'] === true) fns.delete(it);
|
|
163
|
+
};
|
|
164
|
+
const scheduler = it['scheduler'] || fns['scheduler'];
|
|
165
|
+
if (scheduler) {
|
|
166
|
+
scheduler(doCall, ...args);
|
|
167
|
+
} else {
|
|
168
|
+
it(...args);
|
|
169
|
+
if (it['once'] === true) fns.delete(it);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
emitImmediate(type, ...args) {
|
|
173
|
+
const fns = this.subMap.get(type);
|
|
174
|
+
const allSub = this.subMap.get(ALL);
|
|
175
|
+
fns === null || fns === void 0 ? void 0 : fns.forEach(it => this.callSub(it, fns, args));
|
|
176
|
+
allSub === null || allSub === void 0 ? void 0 : allSub.forEach(it => this.callSub(it, allSub, args));
|
|
177
|
+
}
|
|
178
|
+
emitQueue(type, ...args) {
|
|
179
|
+
this.eventQueue.push({
|
|
180
|
+
type,
|
|
181
|
+
args,
|
|
182
|
+
time: timestamp()
|
|
183
|
+
});
|
|
184
|
+
this.process();
|
|
87
185
|
}
|
|
88
|
-
list.push(value);
|
|
89
186
|
}
|
|
187
|
+
BaseEvent.a = 19;
|
|
90
188
|
|
|
189
|
+
const evt = new BaseEvent();
|
|
91
190
|
const G = {
|
|
92
191
|
/** 原子 signal 更新次数 */
|
|
93
192
|
version: 0,
|
|
@@ -95,11 +194,12 @@ const G = {
|
|
|
95
194
|
/** scope 销毁任务序号 */
|
|
96
195
|
scopeDisposeI: 0
|
|
97
196
|
};
|
|
98
|
-
const dirtyLeafs = SortMap();
|
|
197
|
+
const dirtyLeafs = new SortMap();
|
|
99
198
|
var State;
|
|
100
199
|
(function (State) {
|
|
101
200
|
State[State["Clean"] = 0] = "Clean";
|
|
102
201
|
/** 仅用于 scope 节点是否 abort */
|
|
202
|
+
State[State["ScopeAborted"] = 64] = "ScopeAborted";
|
|
103
203
|
State[State["ScopeAbort"] = 32] = "ScopeAbort";
|
|
104
204
|
State[State["OutLink"] = 16] = "OutLink";
|
|
105
205
|
State[State["Unknown"] = 8] = "Unknown";
|
|
@@ -108,294 +208,7 @@ var State;
|
|
|
108
208
|
State[State["ScopeReady"] = 1] = "ScopeReady";
|
|
109
209
|
})(State || (State = {}));
|
|
110
210
|
const DirtyState = State.Unknown | State.Dirty;
|
|
111
|
-
|
|
112
|
-
exports.Scheduler = void 0;
|
|
113
|
-
(function (Scheduler) {
|
|
114
|
-
Scheduler["Sync"] = "__Sync_";
|
|
115
|
-
Scheduler["Layout"] = "__Layout_";
|
|
116
|
-
Scheduler["Micro"] = "__Micro_";
|
|
117
|
-
Scheduler["Macro"] = "__Macro_";
|
|
118
|
-
})(exports.Scheduler || (exports.Scheduler = {}));
|
|
119
|
-
const _scheduler = {
|
|
120
|
-
[exports.Scheduler.Sync]: defaultScheduler,
|
|
121
|
-
[exports.Scheduler.Micro]: microScheduler,
|
|
122
|
-
[exports.Scheduler.Macro]: macroScheduler,
|
|
123
|
-
[exports.Scheduler.Layout]: schedulerLayout
|
|
124
|
-
};
|
|
125
|
-
const scheduler = (key, value) => _scheduler[key] = value;
|
|
126
|
-
function defaultScheduler(effects) {
|
|
127
|
-
for (const effect of effects) {
|
|
128
|
-
effect.runIfDirty();
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
const p = Promise.resolve();
|
|
132
|
-
let hasMicroTask = false;
|
|
133
|
-
function microScheduler(effects) {
|
|
134
|
-
if (hasMicroTask) return;
|
|
135
|
-
p.then(() => {
|
|
136
|
-
defaultScheduler(effects);
|
|
137
|
-
hasMicroTask = false;
|
|
138
|
-
});
|
|
139
|
-
hasMicroTask = true;
|
|
140
|
-
}
|
|
141
|
-
let channel, macroQueue;
|
|
142
|
-
if (globalThis.MessageChannel) {
|
|
143
|
-
channel = new MessageChannel();
|
|
144
|
-
macroQueue = Queue();
|
|
145
|
-
channel.port2.onmessage = () => {
|
|
146
|
-
while (macroQueue.first) {
|
|
147
|
-
macroQueue.shift()();
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
function macroScheduler(effects) {
|
|
152
|
-
if (channel) {
|
|
153
|
-
macroQueue.push(() => defaultScheduler(effects));
|
|
154
|
-
channel.port1.postMessage('');
|
|
155
|
-
}
|
|
156
|
-
setTimeout(() => {
|
|
157
|
-
defaultScheduler(effects);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
function schedulerLayout(effects) {
|
|
161
|
-
requestAnimationFrame(() => {
|
|
162
|
-
defaultScheduler(effects);
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const DefaultDFSOpt = {
|
|
167
|
-
isUp: false,
|
|
168
|
-
begin: undefined,
|
|
169
|
-
complete: undefined,
|
|
170
|
-
breakStack: [],
|
|
171
|
-
breakLine: undefined,
|
|
172
|
-
breakNode: undefined
|
|
173
|
-
};
|
|
174
|
-
function dfs(root, opt = {}) {
|
|
175
|
-
const {
|
|
176
|
-
isUp,
|
|
177
|
-
begin,
|
|
178
|
-
complete,
|
|
179
|
-
breakStack: lineStack,
|
|
180
|
-
breakLine
|
|
181
|
-
} = {
|
|
182
|
-
...DefaultDFSOpt,
|
|
183
|
-
...opt
|
|
184
|
-
};
|
|
185
|
-
let node = opt.breakNode || root;
|
|
186
|
-
let line = breakLine;
|
|
187
|
-
const listKey = isUp ? 'recStart' : 'emitStart';
|
|
188
|
-
const nodeKey = isUp ? 'upstream' : 'downstream';
|
|
189
|
-
// 向上意味着要找所有节点的入度
|
|
190
|
-
const nextLineKey = isUp ? 'nextRecLine' : 'nextEmitLine';
|
|
191
|
-
const reverseNodeKey = isUp ? 'downstream' : 'upstream';
|
|
192
|
-
while (1) {
|
|
193
|
-
let notGoDeep = begin === null || begin === void 0 ? void 0 : begin({
|
|
194
|
-
node: node,
|
|
195
|
-
lineFromUp: line,
|
|
196
|
-
walkedLine: lineStack
|
|
197
|
-
});
|
|
198
|
-
lineStack.push(line);
|
|
199
|
-
line = node[listKey];
|
|
200
|
-
if (line && !notGoDeep) {
|
|
201
|
-
const firstChild = line[nodeKey];
|
|
202
|
-
node = firstChild;
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
while (1) {
|
|
206
|
-
const noGoSibling = complete === null || complete === void 0 ? void 0 : complete({
|
|
207
|
-
node: node,
|
|
208
|
-
lineToDeep: line,
|
|
209
|
-
walkedLine: lineStack,
|
|
210
|
-
notGoDeep
|
|
211
|
-
});
|
|
212
|
-
// 只对当前不下钻的节点生效
|
|
213
|
-
// notGoDeep = false;
|
|
214
|
-
line = lineStack.pop();
|
|
215
|
-
// 递归出口,回到起点
|
|
216
|
-
if (node === root) {
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
notGoDeep = false;
|
|
220
|
-
const nextLine = line[nextLineKey];
|
|
221
|
-
// 有兄弟节点, 进入外循环,向下遍历兄弟节点
|
|
222
|
-
if (!noGoSibling && nextLine) {
|
|
223
|
-
// 外层循环后会把 sibling line 入栈,这里不需要处理
|
|
224
|
-
line = nextLine;
|
|
225
|
-
node = nextLine[nodeKey];
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
// 没有兄弟节点就上浮
|
|
229
|
-
node = line[reverseNodeKey];
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
function Line_$$$_link(v1, v2) {
|
|
235
|
-
let {
|
|
236
|
-
emitEnd
|
|
237
|
-
} = v1,
|
|
238
|
-
{
|
|
239
|
-
recEnd,
|
|
240
|
-
recStart
|
|
241
|
-
} = v2,
|
|
242
|
-
noRecEnd = !recEnd,
|
|
243
|
-
/** 模拟头节点 */
|
|
244
|
-
head = {
|
|
245
|
-
nextRecLine: recStart
|
|
246
|
-
},
|
|
247
|
-
line;
|
|
248
|
-
recEnd = recEnd || head;
|
|
249
|
-
const {
|
|
250
|
-
nextRecLine
|
|
251
|
-
} = recEnd || {};
|
|
252
|
-
// 没有下一个收到的线
|
|
253
|
-
if (!nextRecLine) {
|
|
254
|
-
line = Line();
|
|
255
|
-
// 内部会处理空链表的情况,即同步头部
|
|
256
|
-
Line.emit_line(v1, line);
|
|
257
|
-
Line.rec_line(v2, line);
|
|
258
|
-
emitEnd && Line.line_line_emit(emitEnd, line);
|
|
259
|
-
!noRecEnd && Line.line_line_rec(recEnd, line);
|
|
260
|
-
}
|
|
261
|
-
// 复用
|
|
262
|
-
else if (nextRecLine.upstream === v1) {
|
|
263
|
-
v2.recEnd = nextRecLine;
|
|
264
|
-
// TODO: link 版本标记
|
|
265
|
-
}
|
|
266
|
-
// 插入(这么做): v1 和 下一个 入度(订阅)节点不同
|
|
267
|
-
// TODO: v2上次真依赖了 v1 只是没检查出来,需要删除原依赖
|
|
268
|
-
else {
|
|
269
|
-
line = Line();
|
|
270
|
-
Line.emit_line(v1, line);
|
|
271
|
-
Line.rec_line(v2, line);
|
|
272
|
-
emitEnd && Line.line_line_emit(emitEnd, line);
|
|
273
|
-
Line.insert_line_rec(recEnd, nextRecLine, line);
|
|
274
|
-
}
|
|
275
|
-
// 消除 head
|
|
276
|
-
for (const key in head) {
|
|
277
|
-
head[key] = undefined;
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
Line.link = Line_$$$_link;
|
|
281
|
-
function Line_$$$_unlink(line) {
|
|
282
|
-
let {
|
|
283
|
-
prevEmitLine,
|
|
284
|
-
nextEmitLine,
|
|
285
|
-
prevRecLine,
|
|
286
|
-
nextRecLine,
|
|
287
|
-
upstream,
|
|
288
|
-
downstream
|
|
289
|
-
} = line;
|
|
290
|
-
line.prevEmitLine = undefined;
|
|
291
|
-
line.nextEmitLine = undefined;
|
|
292
|
-
line.prevRecLine = undefined;
|
|
293
|
-
line.nextRecLine = undefined;
|
|
294
|
-
line.upstream = undefined;
|
|
295
|
-
line.downstream = undefined;
|
|
296
|
-
/** 上游节点发出的线 前一条 关联 后一条 */
|
|
297
|
-
if (prevEmitLine) {
|
|
298
|
-
prevEmitLine.nextEmitLine = nextEmitLine;
|
|
299
|
-
} else {
|
|
300
|
-
// 删除的是首个节点
|
|
301
|
-
upstream.emitStart = nextEmitLine;
|
|
302
|
-
}
|
|
303
|
-
if (nextEmitLine) {
|
|
304
|
-
nextEmitLine.prevEmitLine = prevEmitLine;
|
|
305
|
-
} else {
|
|
306
|
-
// 删除尾节点
|
|
307
|
-
upstream.emitEnd = prevEmitLine;
|
|
308
|
-
}
|
|
309
|
-
/** 下游节点接收的线,我们从 recEnd 开始删除的,
|
|
310
|
-
* 接收信息,不需要设置 recEnd ,
|
|
311
|
-
* 因为 recStart ~ recEnd 是经过上级 get 确认的有用依赖
|
|
312
|
-
* */
|
|
313
|
-
if (prevRecLine) {
|
|
314
|
-
prevRecLine.nextRecLine = nextRecLine;
|
|
315
|
-
} else {
|
|
316
|
-
// 删除的是首个节点,大概率不可能从有依赖 变成无依赖
|
|
317
|
-
downstream.recStart = nextRecLine;
|
|
318
|
-
}
|
|
319
|
-
if (nextRecLine) {
|
|
320
|
-
nextRecLine.prevRecLine = prevRecLine;
|
|
321
|
-
} else {
|
|
322
|
-
// 删除尾节点
|
|
323
|
-
downstream.recEnd = prevRecLine;
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
Line.unlink = Line_$$$_unlink;
|
|
327
|
-
function Line_$$$_unlinkRec(line) {
|
|
328
|
-
// 作为下游,执行完 get 上游节点已经完成了依赖更新,把 recEnd 后的依赖删除即可
|
|
329
|
-
let toDel = line;
|
|
330
|
-
while (toDel) {
|
|
331
|
-
const memoNext = toDel.nextRecLine;
|
|
332
|
-
Line.unlink(toDel);
|
|
333
|
-
toDel = memoNext;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
Line.unlinkRec = Line_$$$_unlinkRec;
|
|
337
|
-
function Line_$$$_unlinkEmit(line) {
|
|
338
|
-
// 作为下游,执行完 get 上游节点已经完成了依赖更新,把 recEnd 后的依赖删除即可
|
|
339
|
-
let toDel = line;
|
|
340
|
-
while (toDel) {
|
|
341
|
-
const memoNext = toDel.nextEmitLine;
|
|
342
|
-
Line.unlink(toDel);
|
|
343
|
-
toDel = memoNext;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
Line.unlinkEmit = Line_$$$_unlinkEmit;
|
|
347
|
-
function Line_$$$_emit_line(upstream, line) {
|
|
348
|
-
if (!upstream.emitStart) {
|
|
349
|
-
upstream.emitStart = line;
|
|
350
|
-
}
|
|
351
|
-
upstream.emitEnd = line;
|
|
352
|
-
line.upstream = upstream;
|
|
353
|
-
}
|
|
354
|
-
Line.emit_line = Line_$$$_emit_line;
|
|
355
|
-
function Line_$$$_rec_line(downstream, line) {
|
|
356
|
-
if (!downstream.recStart) {
|
|
357
|
-
downstream.recStart = line;
|
|
358
|
-
}
|
|
359
|
-
downstream.recEnd = line;
|
|
360
|
-
line.downstream = downstream;
|
|
361
|
-
}
|
|
362
|
-
Line.rec_line = Line_$$$_rec_line;
|
|
363
|
-
function Line_$$$_line_line_emit(l1, l2) {
|
|
364
|
-
if (!l1 || !l2) return;
|
|
365
|
-
l1.nextEmitLine = l2;
|
|
366
|
-
l2.prevEmitLine = l1;
|
|
367
|
-
}
|
|
368
|
-
Line.line_line_emit = Line_$$$_line_line_emit;
|
|
369
|
-
function Line_$$$_line_line_rec(l1, l2) {
|
|
370
|
-
if (!l1 || !l2) return;
|
|
371
|
-
l1.nextRecLine = l2;
|
|
372
|
-
l2.prevRecLine = l1;
|
|
373
|
-
}
|
|
374
|
-
Line.line_line_rec = Line_$$$_line_line_rec;
|
|
375
|
-
function Line_$$$_insert_line_emit(l1, l2, ins) {
|
|
376
|
-
l1.nextEmitLine = ins;
|
|
377
|
-
ins.prevEmitLine = l1;
|
|
378
|
-
l2.prevEmitLine = ins;
|
|
379
|
-
ins.nextEmitLine = l2;
|
|
380
|
-
}
|
|
381
|
-
Line.insert_line_emit = Line_$$$_insert_line_emit;
|
|
382
|
-
function Line_$$$_insert_line_rec(l1, l2, ins) {
|
|
383
|
-
l1.nextRecLine = ins;
|
|
384
|
-
ins.prevRecLine = l1;
|
|
385
|
-
l2.prevRecLine = ins;
|
|
386
|
-
ins.nextRecLine = l2;
|
|
387
|
-
}
|
|
388
|
-
Line.insert_line_rec = Line_$$$_insert_line_rec;
|
|
389
|
-
function Line() {
|
|
390
|
-
return {
|
|
391
|
-
upstream: null,
|
|
392
|
-
prevEmitLine: null,
|
|
393
|
-
nextEmitLine: null,
|
|
394
|
-
downstream: null,
|
|
395
|
-
prevRecLine: null,
|
|
396
|
-
nextRecLine: null
|
|
397
|
-
};
|
|
398
|
-
}
|
|
211
|
+
const ScopeExecuted = State.ScopeReady | State.ScopeAbort | State.ScopeAborted;
|
|
399
212
|
|
|
400
213
|
/**
|
|
401
214
|
* 这是一个优先队列 (满足子节点总是比父节点大)
|
|
@@ -436,11 +249,13 @@ const getLeft = (x, max) => leakI(x * 2 + 1, max);
|
|
|
436
249
|
const getRight = (x, max) => leakI(x * 2 + 2, max);
|
|
437
250
|
const getParent = (x, max) => leakI(x - 1 >>> 1, max);
|
|
438
251
|
const exchange = (arr, i, j) => [arr[i], arr[j]] = [arr[j], arr[i]];
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
252
|
+
class PriorityQueue {
|
|
253
|
+
// 构造函数接受一个compare函数
|
|
254
|
+
// compare返回的-1, 0, 1决定元素是否优先被去除
|
|
255
|
+
constructor(aIsUrgent) {
|
|
256
|
+
this.aIsUrgent = aIsUrgent;
|
|
257
|
+
this.arr = [];
|
|
258
|
+
this.goUp = (arr, current, len) => {
|
|
444
259
|
let i = len - 1;
|
|
445
260
|
while (i > 0) {
|
|
446
261
|
const item = arr[i];
|
|
@@ -456,8 +271,8 @@ function PriorityQueue(aIsUrgent) {
|
|
|
456
271
|
break;
|
|
457
272
|
}
|
|
458
273
|
}
|
|
459
|
-
}
|
|
460
|
-
goDown
|
|
274
|
+
};
|
|
275
|
+
this.goDown = (arr, i) => {
|
|
461
276
|
const len = this.size();
|
|
462
277
|
const half = len >>> 1;
|
|
463
278
|
while (i < half) {
|
|
@@ -478,14 +293,71 @@ function PriorityQueue(aIsUrgent) {
|
|
|
478
293
|
// this.logTree();
|
|
479
294
|
i = point;
|
|
480
295
|
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
// 添加一个元素
|
|
299
|
+
_add(current) {
|
|
300
|
+
// console.log(`加入 ${current}`);
|
|
301
|
+
this.arr.push(current);
|
|
302
|
+
const len = this.size();
|
|
303
|
+
// this.logTree();
|
|
304
|
+
if (len === 1) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
this.goUp(this.arr, current, len);
|
|
308
|
+
}
|
|
309
|
+
add(...items) {
|
|
310
|
+
items.forEach(it => this._add(it));
|
|
311
|
+
}
|
|
312
|
+
// 去除头元素并返回
|
|
313
|
+
poll() {
|
|
314
|
+
const {
|
|
315
|
+
arr
|
|
316
|
+
} = this;
|
|
317
|
+
// console.log(`弹出 ${arr[0]} 把 ${arr[arr.length - 1]} 放置到队头 `);
|
|
318
|
+
const len = this.size();
|
|
319
|
+
if (len <= 2) {
|
|
320
|
+
return arr.shift();
|
|
321
|
+
}
|
|
322
|
+
const last = arr.pop();
|
|
323
|
+
const first = arr[0];
|
|
324
|
+
arr[0] = last;
|
|
325
|
+
// this.logTree();
|
|
326
|
+
this.goDown(this.arr, 0);
|
|
327
|
+
return first;
|
|
328
|
+
}
|
|
329
|
+
// 取得头元素
|
|
330
|
+
peek() {
|
|
331
|
+
return this.arr[0];
|
|
332
|
+
}
|
|
333
|
+
// 取得元素数量
|
|
334
|
+
size() {
|
|
335
|
+
return this.arr.length;
|
|
336
|
+
}
|
|
337
|
+
logTree() {
|
|
338
|
+
const {
|
|
339
|
+
arr
|
|
340
|
+
} = this;
|
|
341
|
+
let i = 0;
|
|
342
|
+
let j = 1;
|
|
343
|
+
let level = 0;
|
|
344
|
+
const matrix = [];
|
|
345
|
+
do {
|
|
346
|
+
matrix.push(arr.slice(i, j));
|
|
347
|
+
i = i * 2 + 1;
|
|
348
|
+
j = i + Math.pow(2, level) + 1;
|
|
349
|
+
level++;
|
|
350
|
+
} while (i < arr.length);
|
|
351
|
+
const last = Math.pow(2, matrix.length - 1);
|
|
352
|
+
const arrStr = JSON.stringify(last);
|
|
353
|
+
const halfLen = arrStr.length >>> 1;
|
|
354
|
+
matrix.forEach(it => {
|
|
355
|
+
const str = JSON.stringify(it);
|
|
356
|
+
const halfIt = str.length >>> 1;
|
|
357
|
+
console.log(str.padStart(halfLen + halfIt, ' '));
|
|
358
|
+
});
|
|
359
|
+
console.log('\n');
|
|
360
|
+
}
|
|
489
361
|
}
|
|
490
362
|
// case 1
|
|
491
363
|
// const pq = new PriorityQueue((a, b) => a - b)
|
|
@@ -513,113 +385,55 @@ function PriorityQueue(aIsUrgent) {
|
|
|
513
385
|
// }
|
|
514
386
|
// console.log(result);
|
|
515
387
|
// [5,4,3,2,1]
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
return;
|
|
388
|
+
|
|
389
|
+
class TaskQueue {
|
|
390
|
+
constructor(callbackAble, aIsUrgent) {
|
|
391
|
+
this.callbackAble = callbackAble;
|
|
392
|
+
this.aIsUrgent = aIsUrgent;
|
|
393
|
+
this.isScheduling = false;
|
|
523
394
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
arr
|
|
532
|
-
} = this;
|
|
533
|
-
// console.log(`弹出 ${arr[0]} 把 ${arr[arr.length - 1]} 放置到队头 `);
|
|
534
|
-
const len = this.size();
|
|
535
|
-
if (len <= 2) {
|
|
536
|
-
return arr.shift();
|
|
395
|
+
static create({
|
|
396
|
+
callbackAble,
|
|
397
|
+
aIsUrgent
|
|
398
|
+
}) {
|
|
399
|
+
const queue = new TaskQueue(callbackAble, aIsUrgent);
|
|
400
|
+
queue.taskQueue = new PriorityQueue(aIsUrgent);
|
|
401
|
+
return queue;
|
|
537
402
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
}
|
|
548
|
-
function PriorityQueue_$$$_size() {
|
|
549
|
-
return this.arr.length;
|
|
550
|
-
}
|
|
551
|
-
function PriorityQueue_$$$_logTree() {
|
|
552
|
-
const {
|
|
553
|
-
arr
|
|
554
|
-
} = this;
|
|
555
|
-
let i = 0;
|
|
556
|
-
let j = 1;
|
|
557
|
-
let level = 0;
|
|
558
|
-
const matrix = [];
|
|
559
|
-
do {
|
|
560
|
-
matrix.push(arr.slice(i, j));
|
|
561
|
-
i = i * 2 + 1;
|
|
562
|
-
j = i + Math.pow(2, level) + 1;
|
|
563
|
-
level++;
|
|
564
|
-
} while (i < arr.length);
|
|
565
|
-
const last = Math.pow(2, matrix.length - 1);
|
|
566
|
-
const arrStr = JSON.stringify(last);
|
|
567
|
-
const halfLen = arrStr.length >>> 1;
|
|
568
|
-
matrix.forEach(it => {
|
|
569
|
-
const str = JSON.stringify(it);
|
|
570
|
-
const halfIt = str.length >>> 1;
|
|
571
|
-
console.log(str.padStart(halfLen + halfIt, ' '));
|
|
572
|
-
});
|
|
573
|
-
console.log('\n');
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
function TaskQueue_$$$_create({
|
|
577
|
-
callbackAble,
|
|
578
|
-
aIsUrgent
|
|
579
|
-
}) {
|
|
580
|
-
const queue = TaskQueue(callbackAble, aIsUrgent);
|
|
581
|
-
queue.taskQueue = PriorityQueue(aIsUrgent);
|
|
582
|
-
return queue;
|
|
583
|
-
}
|
|
584
|
-
TaskQueue.create = TaskQueue_$$$_create;
|
|
585
|
-
function TaskQueue(callbackAble, aIsUrgent) {
|
|
586
|
-
return {
|
|
587
|
-
callbackAble: callbackAble,
|
|
588
|
-
aIsUrgent: aIsUrgent,
|
|
589
|
-
isScheduling: false,
|
|
590
|
-
pushTask: TaskQueue_$$$_pushTask,
|
|
591
|
-
scheduleTask: TaskQueue_$$$_scheduleTask
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
function TaskQueue_$$$_pushTask(task) {
|
|
595
|
-
const {
|
|
596
|
-
taskQueue,
|
|
597
|
-
isScheduling
|
|
598
|
-
} = this;
|
|
599
|
-
taskQueue._add(task);
|
|
600
|
-
if (!isScheduling) {
|
|
601
|
-
this.callbackAble(this.scheduleTask.bind(this));
|
|
602
|
-
this.isScheduling = true;
|
|
403
|
+
pushTask(task) {
|
|
404
|
+
const {
|
|
405
|
+
taskQueue,
|
|
406
|
+
isScheduling
|
|
407
|
+
} = this;
|
|
408
|
+
taskQueue._add(task);
|
|
409
|
+
if (!isScheduling) {
|
|
410
|
+
this.callbackAble(this.scheduleTask.bind(this));
|
|
411
|
+
this.isScheduling = true;
|
|
412
|
+
}
|
|
603
413
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
414
|
+
scheduleTask() {
|
|
415
|
+
const {
|
|
416
|
+
taskQueue
|
|
417
|
+
} = this;
|
|
418
|
+
// console.log('调度 dispose');
|
|
419
|
+
const fn = taskQueue.peek();
|
|
420
|
+
if (!fn) return this.isScheduling = false;
|
|
421
|
+
const hasRemain = fn();
|
|
422
|
+
// 未完成
|
|
423
|
+
if (hasRemain) {
|
|
424
|
+
this.callbackAble(this.scheduleTask.bind(this));
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
// 完成
|
|
428
|
+
taskQueue.poll();
|
|
429
|
+
evt.emit('one', fn);
|
|
430
|
+
if (taskQueue.size() === 0) {
|
|
431
|
+
evt.emit('done', fn);
|
|
432
|
+
return this.isScheduling = false;
|
|
433
|
+
}
|
|
434
|
+
// 任务列表中还有任务
|
|
615
435
|
this.callbackAble(this.scheduleTask.bind(this));
|
|
616
|
-
return;
|
|
617
436
|
}
|
|
618
|
-
// 完成
|
|
619
|
-
taskQueue.poll();
|
|
620
|
-
if (taskQueue.size() === 0) return this.isScheduling = false;
|
|
621
|
-
// 任务列表中还有任务
|
|
622
|
-
this.callbackAble(this.scheduleTask.bind(this));
|
|
623
437
|
}
|
|
624
438
|
|
|
625
439
|
const ide = globalThis.requestIdleCallback || (globalThis.requestAnimationFrame ? fn => globalThis.requestAnimationFrame(() => {
|
|
@@ -631,37 +445,308 @@ const now = () => {
|
|
|
631
445
|
const timer = globalThis.performance || globalThis.Date;
|
|
632
446
|
return timer.now();
|
|
633
447
|
};
|
|
448
|
+
let channel = globalThis.MessageChannel ? new MessageChannel() : null;
|
|
449
|
+
if (globalThis.MessageChannel) {
|
|
450
|
+
channel = new MessageChannel();
|
|
451
|
+
}
|
|
452
|
+
let msgId = 0;
|
|
453
|
+
const macro = fn => {
|
|
454
|
+
if (!channel) {
|
|
455
|
+
setTimeout(fn);
|
|
456
|
+
}
|
|
457
|
+
const memoId = msgId;
|
|
458
|
+
function onMessage(e) {
|
|
459
|
+
if (memoId === e.data) {
|
|
460
|
+
fn();
|
|
461
|
+
channel.port2.removeEventListener('message', onMessage);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
channel.port2.addEventListener('message', onMessage);
|
|
465
|
+
channel.port1.postMessage(msgId++);
|
|
466
|
+
};
|
|
467
|
+
const p = Promise.resolve();
|
|
468
|
+
const micro = cb => {
|
|
469
|
+
p.then(cb);
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
exports.Scheduler = void 0;
|
|
473
|
+
(function (Scheduler) {
|
|
474
|
+
Scheduler["Sync"] = "__Sync_";
|
|
475
|
+
Scheduler["Layout"] = "__Layout_";
|
|
476
|
+
Scheduler["Micro"] = "__Micro_";
|
|
477
|
+
Scheduler["Macro"] = "__Macro_";
|
|
478
|
+
})(exports.Scheduler || (exports.Scheduler = {}));
|
|
479
|
+
const _scheduler = {
|
|
480
|
+
[exports.Scheduler.Sync]: defaultScheduler,
|
|
481
|
+
[exports.Scheduler.Micro]: microScheduler,
|
|
482
|
+
[exports.Scheduler.Macro]: macroScheduler,
|
|
483
|
+
[exports.Scheduler.Layout]: layoutScheduler
|
|
484
|
+
};
|
|
485
|
+
const scheduler = (key, value) => _scheduler[key] = value;
|
|
486
|
+
function defaultScheduler(effects) {
|
|
487
|
+
for (const effect of effects) {
|
|
488
|
+
effect.runIfDirty();
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
let microSTaskQueue;
|
|
492
|
+
let macroSTaskQueue;
|
|
493
|
+
let layoutSTaskQueue;
|
|
494
|
+
function microScheduler(effects) {
|
|
495
|
+
microSTaskQueue = microSTaskQueue || TaskQueue.create({
|
|
496
|
+
callbackAble: micro,
|
|
497
|
+
aIsUrgent: (a, b) => a.time < b.time
|
|
498
|
+
});
|
|
499
|
+
microSTaskQueue.pushTask(defaultScheduler.bind(undefined, effects));
|
|
500
|
+
}
|
|
501
|
+
function macroScheduler(effects) {
|
|
502
|
+
macroSTaskQueue = macroSTaskQueue || TaskQueue.create({
|
|
503
|
+
callbackAble: macro,
|
|
504
|
+
aIsUrgent: (a, b) => a.time < b.time
|
|
505
|
+
});
|
|
506
|
+
macroSTaskQueue.pushTask(defaultScheduler.bind(undefined, effects));
|
|
507
|
+
}
|
|
508
|
+
function layoutScheduler(effects) {
|
|
509
|
+
layoutSTaskQueue = layoutSTaskQueue || TaskQueue.create({
|
|
510
|
+
callbackAble: macro,
|
|
511
|
+
aIsUrgent: (a, b) => a.time < b.time
|
|
512
|
+
});
|
|
513
|
+
layoutSTaskQueue.pushTask(defaultScheduler.bind(undefined, effects));
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
const DefaultDFSOpt = {
|
|
517
|
+
isUp: false,
|
|
518
|
+
begin: undefined,
|
|
519
|
+
complete: undefined,
|
|
520
|
+
breakStack: [],
|
|
521
|
+
breakLine: undefined,
|
|
522
|
+
breakNode: undefined
|
|
523
|
+
};
|
|
524
|
+
function dfs(root, opt = {}) {
|
|
525
|
+
const {
|
|
526
|
+
isUp,
|
|
527
|
+
begin,
|
|
528
|
+
complete,
|
|
529
|
+
breakStack: lineStack,
|
|
530
|
+
breakLine
|
|
531
|
+
} = {
|
|
532
|
+
...DefaultDFSOpt,
|
|
533
|
+
...opt
|
|
534
|
+
};
|
|
535
|
+
let node = opt.breakNode || root;
|
|
536
|
+
let line = breakLine;
|
|
537
|
+
const listKey = isUp ? 'recStart' : 'emitStart';
|
|
538
|
+
const nodeKey = isUp ? 'upstream' : 'downstream';
|
|
539
|
+
// 向上意味着要找所有节点的入度
|
|
540
|
+
const nextLineKey = isUp ? 'nextRecLine' : 'nextEmitLine';
|
|
541
|
+
const reverseNodeKey = isUp ? 'downstream' : 'upstream';
|
|
542
|
+
while (1) {
|
|
543
|
+
let notGoDeep = begin === null || begin === void 0 ? void 0 : begin({
|
|
544
|
+
node: node,
|
|
545
|
+
lineFromUp: line,
|
|
546
|
+
walkedLine: lineStack
|
|
547
|
+
});
|
|
548
|
+
lineStack.push(line);
|
|
549
|
+
line = node[listKey];
|
|
550
|
+
if (line && !notGoDeep) {
|
|
551
|
+
const firstChild = line[nodeKey];
|
|
552
|
+
node = firstChild;
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
while (1) {
|
|
556
|
+
const noGoSibling = complete === null || complete === void 0 ? void 0 : complete({
|
|
557
|
+
node: node,
|
|
558
|
+
lineToDeep: line,
|
|
559
|
+
walkedLine: lineStack,
|
|
560
|
+
notGoDeep
|
|
561
|
+
});
|
|
562
|
+
// 只对当前不下钻的节点生效
|
|
563
|
+
// notGoDeep = false;
|
|
564
|
+
line = lineStack.pop();
|
|
565
|
+
// 递归出口,回到起点
|
|
566
|
+
if (node === root) {
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
notGoDeep = false;
|
|
570
|
+
const nextLine = line[nextLineKey];
|
|
571
|
+
// 有兄弟节点, 进入外循环,向下遍历兄弟节点
|
|
572
|
+
if (!noGoSibling && nextLine) {
|
|
573
|
+
// 外层循环后会把 sibling line 入栈,这里不需要处理
|
|
574
|
+
line = nextLine;
|
|
575
|
+
node = nextLine[nodeKey];
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
// 没有兄弟节点就上浮
|
|
579
|
+
node = line[reverseNodeKey];
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
class Line {
|
|
585
|
+
static link(v1, v2) {
|
|
586
|
+
let {
|
|
587
|
+
emitEnd
|
|
588
|
+
} = v1,
|
|
589
|
+
{
|
|
590
|
+
recEnd,
|
|
591
|
+
recStart
|
|
592
|
+
} = v2,
|
|
593
|
+
noRecEnd = !recEnd,
|
|
594
|
+
/** 模拟头节点 */
|
|
595
|
+
head = {
|
|
596
|
+
nextRecLine: recStart
|
|
597
|
+
},
|
|
598
|
+
line;
|
|
599
|
+
recEnd = recEnd || head;
|
|
600
|
+
const {
|
|
601
|
+
nextRecLine
|
|
602
|
+
} = recEnd || {};
|
|
603
|
+
// 没有下一个收到的线
|
|
604
|
+
if (!nextRecLine) {
|
|
605
|
+
line = new Line();
|
|
606
|
+
// 内部会处理空链表的情况,即同步头部
|
|
607
|
+
Line.emit_line(v1, line);
|
|
608
|
+
Line.rec_line(v2, line);
|
|
609
|
+
emitEnd && Line.line_line_emit(emitEnd, line);
|
|
610
|
+
!noRecEnd && Line.line_line_rec(recEnd, line);
|
|
611
|
+
}
|
|
612
|
+
// 复用
|
|
613
|
+
else if (nextRecLine.upstream === v1) {
|
|
614
|
+
v2.recEnd = nextRecLine;
|
|
615
|
+
// TODO: link 版本标记
|
|
616
|
+
}
|
|
617
|
+
// 插入(这么做): v1 和 下一个 入度(订阅)节点不同
|
|
618
|
+
// TODO: v2上次真依赖了 v1 只是没检查出来,需要删除原依赖
|
|
619
|
+
else {
|
|
620
|
+
line = new Line();
|
|
621
|
+
Line.emit_line(v1, line);
|
|
622
|
+
Line.rec_line(v2, line);
|
|
623
|
+
emitEnd && Line.line_line_emit(emitEnd, line);
|
|
624
|
+
Line.insert_line_rec(recEnd, nextRecLine, line);
|
|
625
|
+
}
|
|
626
|
+
// 消除 head
|
|
627
|
+
for (const key in head) {
|
|
628
|
+
head[key] = undefined;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
static unlink(line) {
|
|
632
|
+
let {
|
|
633
|
+
prevEmitLine,
|
|
634
|
+
nextEmitLine,
|
|
635
|
+
prevRecLine,
|
|
636
|
+
nextRecLine,
|
|
637
|
+
upstream,
|
|
638
|
+
downstream
|
|
639
|
+
} = line;
|
|
640
|
+
line.prevEmitLine = undefined;
|
|
641
|
+
line.nextEmitLine = undefined;
|
|
642
|
+
line.prevRecLine = undefined;
|
|
643
|
+
line.nextRecLine = undefined;
|
|
644
|
+
line.upstream = undefined;
|
|
645
|
+
line.downstream = undefined;
|
|
646
|
+
/** 上游节点发出的线 前一条 关联 后一条 */
|
|
647
|
+
if (prevEmitLine) {
|
|
648
|
+
prevEmitLine.nextEmitLine = nextEmitLine;
|
|
649
|
+
} else {
|
|
650
|
+
// 删除的是首个节点
|
|
651
|
+
upstream.emitStart = nextEmitLine;
|
|
652
|
+
}
|
|
653
|
+
if (nextEmitLine) {
|
|
654
|
+
nextEmitLine.prevEmitLine = prevEmitLine;
|
|
655
|
+
} else {
|
|
656
|
+
// 删除尾节点
|
|
657
|
+
upstream.emitEnd = prevEmitLine;
|
|
658
|
+
}
|
|
659
|
+
/** 下游节点接收的线,我们从 recEnd 开始删除的,
|
|
660
|
+
* 接收信息,不需要设置 recEnd ,
|
|
661
|
+
* 因为 recStart ~ recEnd 是经过上级 get 确认的有用依赖
|
|
662
|
+
* */
|
|
663
|
+
if (prevRecLine) {
|
|
664
|
+
prevRecLine.nextRecLine = nextRecLine;
|
|
665
|
+
} else {
|
|
666
|
+
// 删除的是首个节点,大概率不可能从有依赖 变成无依赖
|
|
667
|
+
downstream.recStart = nextRecLine;
|
|
668
|
+
}
|
|
669
|
+
if (nextRecLine) {
|
|
670
|
+
nextRecLine.prevRecLine = prevRecLine;
|
|
671
|
+
} else {
|
|
672
|
+
// 删除尾节点
|
|
673
|
+
downstream.recEnd = prevRecLine;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
static unlinkRec(line) {
|
|
677
|
+
// 作为下游,执行完 get 上游节点已经完成了依赖更新,把 recEnd 后的依赖删除即可
|
|
678
|
+
let toDel = line;
|
|
679
|
+
while (toDel) {
|
|
680
|
+
const memoNext = toDel.nextRecLine;
|
|
681
|
+
Line.unlink(toDel);
|
|
682
|
+
toDel = memoNext;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
static unlinkEmit(line) {
|
|
686
|
+
// 作为下游,执行完 get 上游节点已经完成了依赖更新,把 recEnd 后的依赖删除即可
|
|
687
|
+
let toDel = line;
|
|
688
|
+
while (toDel) {
|
|
689
|
+
const memoNext = toDel.nextEmitLine;
|
|
690
|
+
Line.unlink(toDel);
|
|
691
|
+
toDel = memoNext;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
/** 上游节点 连 link */
|
|
695
|
+
static emit_line(upstream, line) {
|
|
696
|
+
if (!upstream.emitStart) {
|
|
697
|
+
upstream.emitStart = line;
|
|
698
|
+
}
|
|
699
|
+
upstream.emitEnd = line;
|
|
700
|
+
line.upstream = upstream;
|
|
701
|
+
}
|
|
702
|
+
/** 下游节点 连 link */
|
|
703
|
+
static rec_line(downstream, line) {
|
|
704
|
+
if (!downstream.recStart) {
|
|
705
|
+
downstream.recStart = line;
|
|
706
|
+
}
|
|
707
|
+
downstream.recEnd = line;
|
|
708
|
+
line.downstream = downstream;
|
|
709
|
+
}
|
|
710
|
+
/** 同一节点发出的 两个条线 相连 */
|
|
711
|
+
static line_line_emit(l1, l2) {
|
|
712
|
+
if (!l1 || !l2) return;
|
|
713
|
+
l1.nextEmitLine = l2;
|
|
714
|
+
l2.prevEmitLine = l1;
|
|
715
|
+
}
|
|
716
|
+
/** 同一节点接收的 两个条线 相连 */
|
|
717
|
+
static line_line_rec(l1, l2) {
|
|
718
|
+
if (!l1 || !l2) return;
|
|
719
|
+
l1.nextRecLine = l2;
|
|
720
|
+
l2.prevRecLine = l1;
|
|
721
|
+
}
|
|
722
|
+
static insert_line_emit(l1, l2, ins) {
|
|
723
|
+
l1.nextEmitLine = ins;
|
|
724
|
+
ins.prevEmitLine = l1;
|
|
725
|
+
l2.prevEmitLine = ins;
|
|
726
|
+
ins.nextEmitLine = l2;
|
|
727
|
+
}
|
|
728
|
+
static insert_line_rec(l1, l2, ins) {
|
|
729
|
+
l1.nextRecLine = ins;
|
|
730
|
+
ins.prevRecLine = l1;
|
|
731
|
+
l2.prevRecLine = ins;
|
|
732
|
+
ins.nextRecLine = l2;
|
|
733
|
+
}
|
|
734
|
+
constructor() {
|
|
735
|
+
/** 上游顶点 */
|
|
736
|
+
this.upstream = null;
|
|
737
|
+
/** 上游节点 发出的上一条线 */
|
|
738
|
+
this.prevEmitLine = null;
|
|
739
|
+
/** 上游节点 发出的下一条线 */
|
|
740
|
+
this.nextEmitLine = null;
|
|
741
|
+
/** 下游顶点 */
|
|
742
|
+
this.downstream = null;
|
|
743
|
+
/** 下游节点 接收的上一条线 */
|
|
744
|
+
this.prevRecLine = null;
|
|
745
|
+
/** 下游节点 接收的下一条线 */
|
|
746
|
+
this.nextRecLine = null;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
634
749
|
|
|
635
|
-
// export class IdeScheduler {
|
|
636
|
-
// constructor() {}
|
|
637
|
-
// isScheduling = false;
|
|
638
|
-
// taskQueue = new Queue<Function>();
|
|
639
|
-
// pushTask(task: Function) {
|
|
640
|
-
// const { taskQueue, isScheduling } = this;
|
|
641
|
-
// taskQueue.push(task);
|
|
642
|
-
// if (!isScheduling) {
|
|
643
|
-
// ide(this.scheduleTask.bind(this));
|
|
644
|
-
// this.isScheduling = true;
|
|
645
|
-
// }
|
|
646
|
-
// }
|
|
647
|
-
// scheduleTask() {
|
|
648
|
-
// const { taskQueue } = this;
|
|
649
|
-
// // console.log('调度 dispose');
|
|
650
|
-
// const fn = taskQueue.first;
|
|
651
|
-
// if (!fn) return (this.isScheduling = false);
|
|
652
|
-
// const hasRemain = fn();
|
|
653
|
-
// // 未完成
|
|
654
|
-
// if (hasRemain) {
|
|
655
|
-
// ide(this.scheduleTask.bind(this));
|
|
656
|
-
// return;
|
|
657
|
-
// }
|
|
658
|
-
// // 完成
|
|
659
|
-
// taskQueue.shift();
|
|
660
|
-
// if (taskQueue.len === 0) return (this.isScheduling = false);
|
|
661
|
-
// // 任务列表中还有任务
|
|
662
|
-
// ide(this.scheduleTask.bind(this));
|
|
663
|
-
// }
|
|
664
|
-
// }
|
|
665
750
|
/** scope 捕获,引用外部 signal 孤岛 */
|
|
666
751
|
const unTrackIsland = signal => {
|
|
667
752
|
// 原来是孤岛,且被 scope 管理的要恢复
|
|
@@ -671,7 +756,7 @@ const unTrackIsland = signal => {
|
|
|
671
756
|
};
|
|
672
757
|
/** scope 释放,被重新连接的孤岛 */
|
|
673
758
|
const trackIsland = signal => {
|
|
674
|
-
const line = Line();
|
|
759
|
+
const line = new Line();
|
|
675
760
|
// 上游节点处于孤岛状态,切有引用外部信号,需要被 scope 管理来删除外部依赖
|
|
676
761
|
if (!signal.emitStart && signal.state & State.OutLink) {
|
|
677
762
|
const {
|
|
@@ -682,6 +767,16 @@ const trackIsland = signal => {
|
|
|
682
767
|
Line.line_line_rec(recEnd, line);
|
|
683
768
|
}
|
|
684
769
|
};
|
|
770
|
+
/** 子 scope 释放,把其 only 被其持有的 signal 挂回其属于的 scope */
|
|
771
|
+
const trackByOtherScopeDispose = signal => {
|
|
772
|
+
const line = new Line();
|
|
773
|
+
const {
|
|
774
|
+
recEnd
|
|
775
|
+
} = signal.scope;
|
|
776
|
+
Line.emit_line(signal, line);
|
|
777
|
+
Line.rec_line(signal.scope, line);
|
|
778
|
+
Line.line_line_rec(recEnd, line);
|
|
779
|
+
};
|
|
685
780
|
const markOutLink = (signal, downstream) => {
|
|
686
781
|
// 上游是外部节点,或者上游引用了外部节点的, 做传播
|
|
687
782
|
if (signal.scope !== downstream.scope || signal.state & State.OutLink) {
|
|
@@ -703,13 +798,16 @@ const ideScheduler = TaskQueue.create({
|
|
|
703
798
|
return a.index < b.index;
|
|
704
799
|
}
|
|
705
800
|
});
|
|
706
|
-
function handleOneTask(
|
|
801
|
+
function handleOneTask(scope, breakStack) {
|
|
707
802
|
breakStack = remain.stack || breakStack;
|
|
708
803
|
// 将 s 同步到 remainRoot
|
|
709
804
|
let lineToRemove = null;
|
|
710
805
|
const startTime = now();
|
|
806
|
+
if (scope.emitStart) {
|
|
807
|
+
Line.unlink(scope.emitStart);
|
|
808
|
+
}
|
|
711
809
|
try {
|
|
712
|
-
dfs(
|
|
810
|
+
dfs(scope, {
|
|
713
811
|
breakStack,
|
|
714
812
|
breakNode: remain.node,
|
|
715
813
|
breakLine: remain.line,
|
|
@@ -731,9 +829,28 @@ function handleOneTask(s, breakStack) {
|
|
|
731
829
|
};
|
|
732
830
|
throw BreakErr;
|
|
733
831
|
}
|
|
832
|
+
// 1. 未标记的节点,是外部节点
|
|
734
833
|
if (!(node.state & State.OutLink)) {
|
|
735
834
|
return true;
|
|
736
835
|
}
|
|
836
|
+
// 2. 标记的节点,但是 scope 不一样,说明外部节点也引用了 另一 scope 的节点
|
|
837
|
+
if (lineFromUp && node.scope !== lineFromUp.downstream['scope']) {
|
|
838
|
+
// 是仅被 node 引用的外部节点
|
|
839
|
+
if (node.emitStart === node.emitEnd) {
|
|
840
|
+
// 已经 abort 只能继续释放
|
|
841
|
+
if (scope.state & State.ScopeAborted) {
|
|
842
|
+
const bound = handleOneTask.bind(undefined, node, []);
|
|
843
|
+
bound.index = G.scopeDisposeI++;
|
|
844
|
+
ideScheduler.pushTask(bound);
|
|
845
|
+
}
|
|
846
|
+
// 可以将其交给 原 scope 释放
|
|
847
|
+
else {
|
|
848
|
+
trackByOtherScopeDispose(node);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
// 任何外部引用都应该被断开
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
737
854
|
// 对于嵌套作用域不允许重复进入
|
|
738
855
|
node.state &= ~State.OutLink;
|
|
739
856
|
},
|
|
@@ -761,6 +878,7 @@ function handleOneTask(s, breakStack) {
|
|
|
761
878
|
node: null,
|
|
762
879
|
line: null
|
|
763
880
|
};
|
|
881
|
+
scope.state |= State.ScopeAborted;
|
|
764
882
|
} catch (error) {
|
|
765
883
|
if (error === BreakErr) return true;
|
|
766
884
|
remain = {
|
|
@@ -784,20 +902,6 @@ function unlinkRecWithScope(line) {
|
|
|
784
902
|
}
|
|
785
903
|
}
|
|
786
904
|
|
|
787
|
-
function Signal_$$$_create(nextValue, {
|
|
788
|
-
customPull,
|
|
789
|
-
isScope,
|
|
790
|
-
...rest
|
|
791
|
-
}) {
|
|
792
|
-
const s = Signal(nextValue, customPull);
|
|
793
|
-
s.pull = s.customPull || s.DEFAULT_PULL;
|
|
794
|
-
Object.assign(s, rest);
|
|
795
|
-
if (isScope) {
|
|
796
|
-
s.scope = s;
|
|
797
|
-
}
|
|
798
|
-
return s;
|
|
799
|
-
}
|
|
800
|
-
Signal.create = Signal_$$$_create;
|
|
801
905
|
const markDeep = signal => {
|
|
802
906
|
let level = 0;
|
|
803
907
|
dfs(signal, {
|
|
@@ -834,200 +938,208 @@ const markDeep = signal => {
|
|
|
834
938
|
}
|
|
835
939
|
dirtyLeafs.clear();
|
|
836
940
|
};
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
nextValue
|
|
844
|
-
customPull
|
|
845
|
-
version
|
|
846
|
-
id
|
|
847
|
-
state
|
|
848
|
-
scope
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
pullRecurse: Signal_$$$_pullRecurse,
|
|
858
|
-
pullDeep: Signal_$$$_pullDeep,
|
|
859
|
-
get: Signal_$$$_get,
|
|
860
|
-
markDownStreamsDirty: Signal_$$$_markDownStreamsDirty,
|
|
861
|
-
set: Signal_$$$_set,
|
|
862
|
-
run: Signal_$$$_run,
|
|
863
|
-
runIfDirty: Signal_$$$_runIfDirty,
|
|
864
|
-
isAbort: Signal_$$$_isAbort
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
function Signal_$$$_DEFAULT_PULL() {
|
|
868
|
-
return this.nextValue;
|
|
869
|
-
}
|
|
870
|
-
function Signal_$$$_pullRecurse(shouldLink = true) {
|
|
871
|
-
var _a;
|
|
872
|
-
let downstream = Signal.Pulling;
|
|
873
|
-
if (shouldLink && downstream) {
|
|
874
|
-
// 如果上游节点被 scope 管理了,解除管理
|
|
875
|
-
unTrackIsland(this);
|
|
876
|
-
Line.link(this, downstream);
|
|
941
|
+
class Signal {
|
|
942
|
+
constructor(nextValue,
|
|
943
|
+
/** 为什么是 shallow,因为 pullDeep 会把
|
|
944
|
+
* 上游节点 get 执行完成,让其可以直接拿到缓存值
|
|
945
|
+
*/
|
|
946
|
+
customPull) {
|
|
947
|
+
this.nextValue = nextValue;
|
|
948
|
+
this.customPull = customPull;
|
|
949
|
+
this.version = -1;
|
|
950
|
+
this.id = G.id++;
|
|
951
|
+
this.state = State.Clean;
|
|
952
|
+
/** 当前节点创建时处于的 effect 就是 scope */
|
|
953
|
+
this.scope = Signal.Pulling;
|
|
954
|
+
this.recEnd = null;
|
|
955
|
+
this.recStart = null;
|
|
956
|
+
this.emitStart = null;
|
|
957
|
+
this.emitEnd = null;
|
|
958
|
+
this.scheduler = null;
|
|
959
|
+
this.value = null;
|
|
960
|
+
this.pull = null;
|
|
877
961
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
this.pull = this.customPull || this.DEFAULT_PULL;
|
|
889
|
-
this.value = v;
|
|
890
|
-
// 依赖上游的 版本号
|
|
891
|
-
this.version = G.version;
|
|
892
|
-
// if (this.value !== v) {
|
|
893
|
-
// }
|
|
894
|
-
return this.value;
|
|
895
|
-
} catch (error) {
|
|
896
|
-
console.error('计算属性报错这次不触发,后续状态可能出错', error);
|
|
897
|
-
return this.value;
|
|
898
|
-
} finally {
|
|
899
|
-
// 本 getter 执行完成时上游 getter 通过 link,完成对下游 recLines 的更新
|
|
900
|
-
const toDel = (_a = this.recEnd) === null || _a === void 0 ? void 0 : _a.nextRecLine;
|
|
901
|
-
unlinkRecWithScope(toDel);
|
|
902
|
-
if (shouldLink && downstream) {
|
|
903
|
-
// 用于 scope 指示哪些节点依赖 scope 外部
|
|
904
|
-
markOutLink(this, downstream);
|
|
962
|
+
static create(nextValue, {
|
|
963
|
+
customPull,
|
|
964
|
+
isScope,
|
|
965
|
+
...rest
|
|
966
|
+
}) {
|
|
967
|
+
const s = new Signal(nextValue, customPull);
|
|
968
|
+
s.pull = s.customPull || s.DEFAULT_PULL;
|
|
969
|
+
Object.assign(s, rest);
|
|
970
|
+
if (isScope) {
|
|
971
|
+
s.scope = s;
|
|
905
972
|
}
|
|
906
|
-
|
|
973
|
+
return s;
|
|
907
974
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
/*----------------- 有上游节点,通过 dfs 重新计算结果 -----------------*/
|
|
911
|
-
const signal = this;
|
|
912
|
-
// 优化执行
|
|
913
|
-
if (!(signal.state & DirtyState)) {
|
|
914
|
-
return this.value;
|
|
975
|
+
DEFAULT_PULL() {
|
|
976
|
+
return this.nextValue;
|
|
915
977
|
}
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
if (
|
|
929
|
-
return
|
|
978
|
+
/**
|
|
979
|
+
* 递归拉取负责建立以来链
|
|
980
|
+
*/
|
|
981
|
+
pullRecurse(shouldLink = true) {
|
|
982
|
+
var _a;
|
|
983
|
+
let downstream = Signal.Pulling;
|
|
984
|
+
if (shouldLink && downstream) {
|
|
985
|
+
// 如果上游节点被 scope 管理了,解除管理
|
|
986
|
+
unTrackIsland(this);
|
|
987
|
+
Line.link(this, downstream);
|
|
988
|
+
}
|
|
989
|
+
try {
|
|
990
|
+
if (this.version === G.version) {
|
|
991
|
+
return this.value;
|
|
930
992
|
}
|
|
931
|
-
|
|
932
|
-
//
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
993
|
+
this.state &= ~State.OutLink;
|
|
994
|
+
// 进 pullShallow 前重置 recEnd,让子 getter 重构订阅链表
|
|
995
|
+
this.recEnd = undefined;
|
|
996
|
+
Signal.Pulling = this;
|
|
997
|
+
const v = this.pull();
|
|
998
|
+
// 如果使用了 DEFAULT_PULL,处理一次 set 的取值后,替换回 customPull,如果有的话
|
|
999
|
+
this.pull = this.customPull || this.DEFAULT_PULL;
|
|
1000
|
+
this.value = v;
|
|
1001
|
+
// 依赖上游的 版本号
|
|
1002
|
+
this.version = G.version;
|
|
1003
|
+
// if (this.value !== v) {
|
|
1004
|
+
// }
|
|
1005
|
+
return this.value;
|
|
1006
|
+
} catch (error) {
|
|
1007
|
+
console.error('计算属性报错这次不触发,后续状态可能出错', error);
|
|
1008
|
+
return this.value;
|
|
1009
|
+
} finally {
|
|
1010
|
+
// 本 getter 执行完成时上游 getter 通过 link,完成对下游 recLines 的更新
|
|
1011
|
+
const toDel = (_a = this.recEnd) === null || _a === void 0 ? void 0 : _a.nextRecLine;
|
|
1012
|
+
unlinkRecWithScope(toDel);
|
|
1013
|
+
if (shouldLink && downstream) {
|
|
1014
|
+
// 用于 scope 指示哪些节点依赖 scope 外部
|
|
1015
|
+
markOutLink(this, downstream);
|
|
1016
|
+
}
|
|
1017
|
+
Signal.Pulling = downstream;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
pullDeep() {
|
|
1021
|
+
/*----------------- 有上游节点,通过 dfs 重新计算结果 -----------------*/
|
|
1022
|
+
const signal = this;
|
|
1023
|
+
// 优化执行
|
|
1024
|
+
if (!(signal.state & DirtyState)) {
|
|
1025
|
+
return this.value;
|
|
1026
|
+
}
|
|
1027
|
+
dfs(signal, {
|
|
1028
|
+
isUp: true,
|
|
1029
|
+
begin: ({
|
|
1030
|
+
node
|
|
1031
|
+
}) => {
|
|
1032
|
+
// console.log('begin', node.id);
|
|
1033
|
+
/**
|
|
1034
|
+
* 不需要检查
|
|
1035
|
+
* 1. 正在查
|
|
1036
|
+
* 2. 干净
|
|
1037
|
+
* 3. 放弃 或者为 scope 节点
|
|
1038
|
+
*/
|
|
1039
|
+
if (node.state & State.Check || !(node.state & DirtyState) || node.isAbort()) {
|
|
1040
|
+
return true;
|
|
953
1041
|
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
1042
|
+
node.state |= State.Check;
|
|
1043
|
+
// 交给下游重新计算是否 引用外部节点
|
|
1044
|
+
node.state &= ~State.OutLink;
|
|
1045
|
+
},
|
|
1046
|
+
complete: ({
|
|
1047
|
+
node,
|
|
1048
|
+
notGoDeep: currentClean,
|
|
1049
|
+
walkedLine
|
|
1050
|
+
}) => {
|
|
1051
|
+
let noGoSibling = false;
|
|
1052
|
+
const last = walkedLine[walkedLine.length - 1];
|
|
1053
|
+
const downstream = last === null || last === void 0 ? void 0 : last.downstream;
|
|
1054
|
+
// 当前正在检查,生成检查屏障,同时避免重新标记 和
|
|
1055
|
+
if (currentClean) ;
|
|
1056
|
+
// 当前节点需要重新计算
|
|
1057
|
+
else if (node.state & State.Dirty) {
|
|
1058
|
+
// 优化:源节点变化,直接让下游节点重新计算
|
|
1059
|
+
if (!node.recStart && node.value !== node.nextValue) {
|
|
963
1060
|
node.markDownStreamsDirty();
|
|
1061
|
+
node.state &= ~State.Dirty;
|
|
1062
|
+
node.state &= ~State.Check;
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
// 预检数据
|
|
1066
|
+
else {
|
|
1067
|
+
const prevPulling = Signal.Pulling;
|
|
1068
|
+
Signal.Pulling = downstream;
|
|
1069
|
+
const prevValue = node.value;
|
|
1070
|
+
// 递归转用递归拉取,且不需要重建 link 因为dfs的前提就是上游节点依赖于 本节点
|
|
1071
|
+
node.pullRecurse(false);
|
|
1072
|
+
// dirty 传播, 由于本节点值已被计算出,因此消除 dirty
|
|
1073
|
+
if (prevValue !== node.value) {
|
|
1074
|
+
node.markDownStreamsDirty();
|
|
1075
|
+
}
|
|
1076
|
+
node.state &= ~State.Dirty;
|
|
1077
|
+
Signal.Pulling = prevPulling;
|
|
1078
|
+
// 立刻返回父节点重新计算
|
|
1079
|
+
noGoSibling = true;
|
|
964
1080
|
}
|
|
965
|
-
node.state &= ~State.Dirty;
|
|
966
|
-
Signal.Pulling = prevPulling;
|
|
967
|
-
// 立刻返回父节点重新计算
|
|
968
|
-
noGoSibling = true;
|
|
969
1081
|
}
|
|
1082
|
+
// 没被上游节点标记为 Dirty,说明是干净的
|
|
1083
|
+
else if (node.state & State.Unknown) {
|
|
1084
|
+
node.state &= ~State.Unknown;
|
|
1085
|
+
}
|
|
1086
|
+
node.version = G.version;
|
|
1087
|
+
node.state &= ~State.Check;
|
|
1088
|
+
if (downstream) {
|
|
1089
|
+
markOutLink(node, downstream);
|
|
1090
|
+
}
|
|
1091
|
+
return noGoSibling;
|
|
970
1092
|
}
|
|
971
|
-
|
|
972
|
-
else if (node.state & State.Unknown) {
|
|
973
|
-
node.state &= ~State.Unknown;
|
|
974
|
-
}
|
|
975
|
-
node.version = G.version;
|
|
976
|
-
node.state &= ~State.Check;
|
|
977
|
-
if (downstream) {
|
|
978
|
-
markOutLink(node, downstream);
|
|
979
|
-
}
|
|
980
|
-
return noGoSibling;
|
|
981
|
-
}
|
|
982
|
-
});
|
|
983
|
-
return this.value;
|
|
984
|
-
}
|
|
985
|
-
function Signal_$$$_get() {
|
|
986
|
-
if (this.isAbort()) {
|
|
1093
|
+
});
|
|
987
1094
|
return this.value;
|
|
988
1095
|
}
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
1096
|
+
get() {
|
|
1097
|
+
if (this.isAbort()) {
|
|
1098
|
+
return this.value;
|
|
1099
|
+
}
|
|
1100
|
+
// 没有上游节点,应该通过递归重新建立
|
|
1101
|
+
if (!this.recStart) {
|
|
1102
|
+
return this.pullRecurse(true);
|
|
1103
|
+
}
|
|
1104
|
+
// 有上游节点则采用 dfs 直接遍历,查看情况
|
|
1105
|
+
return this.pullDeep();
|
|
992
1106
|
}
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
downstream.state &= ~State.Unknown;
|
|
1002
|
-
point = point.nextEmitLine;
|
|
1107
|
+
markDownStreamsDirty() {
|
|
1108
|
+
let point = this.emitStart;
|
|
1109
|
+
while (point != null) {
|
|
1110
|
+
const downstream = point.downstream;
|
|
1111
|
+
downstream.state |= State.Dirty;
|
|
1112
|
+
downstream.state &= ~State.Unknown;
|
|
1113
|
+
point = point.nextEmitLine;
|
|
1114
|
+
}
|
|
1003
1115
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1116
|
+
set(v) {
|
|
1117
|
+
if (this.isAbort() || this.nextValue === v) {
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
this.nextValue = v;
|
|
1121
|
+
// 手动设值后,采用默认拉取,能拉取到设置的值,拉取完成后在替换回 customPull
|
|
1122
|
+
this.pull = this.DEFAULT_PULL;
|
|
1123
|
+
G.version++;
|
|
1124
|
+
markDeep(this);
|
|
1008
1125
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1126
|
+
run(...args) {
|
|
1127
|
+
if (args.length) {
|
|
1128
|
+
return this.set(args[0]);
|
|
1129
|
+
}
|
|
1130
|
+
return this.get();
|
|
1131
|
+
}
|
|
1132
|
+
runIfDirty() {
|
|
1133
|
+
this.state & (State.Unknown | State.Dirty) && this.run();
|
|
1134
|
+
}
|
|
1135
|
+
isAbort() {
|
|
1136
|
+
return (
|
|
1137
|
+
// scope 被取消
|
|
1138
|
+
this.scope && this.scope.state & State.ScopeAbort ||
|
|
1139
|
+
// 是 scope 节点,且处于 ready 状态,不需要重复执行
|
|
1140
|
+
this === this.scope && this.state & ScopeExecuted
|
|
1141
|
+
);
|
|
1018
1142
|
}
|
|
1019
|
-
return this.get();
|
|
1020
|
-
}
|
|
1021
|
-
function Signal_$$$_runIfDirty() {
|
|
1022
|
-
this.state & (State.Unknown | State.Dirty) && this.run();
|
|
1023
|
-
}
|
|
1024
|
-
function Signal_$$$_isAbort() {
|
|
1025
|
-
return (
|
|
1026
|
-
// scope 被取消
|
|
1027
|
-
this.scope && this.scope.state & State.ScopeAbort ||
|
|
1028
|
-
// 是 scope 节点,且处于 ready 状态,不需要重复执行
|
|
1029
|
-
this === this.scope && this.state & (State.ScopeAbort | State.ScopeReady)
|
|
1030
|
-
);
|
|
1031
1143
|
}
|
|
1032
1144
|
Signal.Pulling = null;
|
|
1033
1145
|
function runWithPulling(fn, signal) {
|
|
@@ -1112,8 +1224,54 @@ const customSignal = opt => {
|
|
|
1112
1224
|
return s;
|
|
1113
1225
|
};
|
|
1114
1226
|
};
|
|
1227
|
+
// const globalSignal = $(10);
|
|
1228
|
+
// let outerA, outerB, innerX, innerY, outerResult, innerResult, innerDispose;
|
|
1229
|
+
// const outerDispose = scope(() => {
|
|
1230
|
+
// outerA = $(1);
|
|
1231
|
+
// outerB = $(2);
|
|
1232
|
+
// // 外层计算信号
|
|
1233
|
+
// outerResult = $(() => {
|
|
1234
|
+
// const res = globalSignal.v + outerA.v + outerB.v;
|
|
1235
|
+
// return res;
|
|
1236
|
+
// });
|
|
1237
|
+
// innerDispose = scope(() => {
|
|
1238
|
+
// innerX = $(3);
|
|
1239
|
+
// innerY = $(4);
|
|
1240
|
+
// // 内层计算信号,既依赖内层也依赖外层信号
|
|
1241
|
+
// innerResult = $(() => {
|
|
1242
|
+
// const res = outerA.v + innerX.v + innerY.v;
|
|
1243
|
+
// return res;
|
|
1244
|
+
// });
|
|
1245
|
+
// // 访问信号以建立依赖关系
|
|
1246
|
+
// innerResult();
|
|
1247
|
+
// });
|
|
1248
|
+
// // 访问外层信号
|
|
1249
|
+
// outerResult();
|
|
1250
|
+
// // 将内层dispose函数绑定到外层scope,这样可以测试嵌套行为
|
|
1251
|
+
// (outerResult as any).innerDispose = innerDispose;
|
|
1252
|
+
// });
|
|
1253
|
+
// outerA.v = 5;
|
|
1254
|
+
// innerX.v = 6;
|
|
1255
|
+
// globalSignal.v = 20;
|
|
1256
|
+
// // 先释放内层scope
|
|
1257
|
+
// innerDispose();
|
|
1258
|
+
// innerX.v = 7;
|
|
1259
|
+
// outerA.v = 8;
|
|
1260
|
+
// outerDispose();
|
|
1261
|
+
// evt.on('one', ({ index }) => {
|
|
1262
|
+
// switch (index) {
|
|
1263
|
+
// case 0:
|
|
1264
|
+
// console.log({ index });
|
|
1265
|
+
// break;
|
|
1266
|
+
// case 1:
|
|
1267
|
+
// console.log({ index });
|
|
1268
|
+
// default:
|
|
1269
|
+
// break;
|
|
1270
|
+
// }
|
|
1271
|
+
// });
|
|
1115
1272
|
|
|
1116
1273
|
exports.$ = $;
|
|
1274
|
+
exports.TaskQueue = TaskQueue;
|
|
1117
1275
|
exports.customSignal = customSignal;
|
|
1118
1276
|
exports.scheduler = scheduler;
|
|
1119
1277
|
exports.scope = scope;
|