iter(g217): 补 frame 内核冒烟并修复 effect 注销
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
// 当前正在收集依赖的 effect;null 表示非追踪态
|
||||
let active: (() => void) | null = null;
|
||||
// 当前 effect 已订阅到的「信号订阅集」集合:重跑前据此清旧订阅,注销时据此摘干净
|
||||
let activeDeps: Set<Set<() => void>> | null = null;
|
||||
|
||||
/*** 响应式信号:无参调用读值并收集依赖,传参写值并触发订阅 ***/
|
||||
export interface Signal<T> {
|
||||
@@ -13,7 +15,10 @@ export function signal<T>(initial: T): Signal<T> {
|
||||
const subs = new Set<() => void>();
|
||||
const read = (...args: unknown[]) => {
|
||||
if (args.length === 0) {
|
||||
if (active) subs.add(active); // 依赖收集
|
||||
if (active) {
|
||||
subs.add(active); // 依赖收集
|
||||
activeDeps?.add(subs); // 同时记下「我订阅了哪个集」,注销时才能摘干净
|
||||
}
|
||||
return value;
|
||||
}
|
||||
const v = args[0] as T;
|
||||
@@ -24,20 +29,30 @@ export function signal<T>(initial: T): Signal<T> {
|
||||
return read as Signal<T>;
|
||||
}
|
||||
|
||||
/*** 副作用:立即执行一次并追踪内部读取的信号,依赖变化自动重跑 ***/
|
||||
/*** 副作用:立即执行一次并追踪内部读取的信号,依赖变化自动重跑;返回注销函数 ***/
|
||||
export function effect(fn: () => void): () => void {
|
||||
const deps = new Set<Set<() => void>>(); // 本 effect 订阅到的所有信号订阅集
|
||||
let stopped = false; // 注销标志:注销后即使还在某个订阅集里也不再执行
|
||||
const run = () => {
|
||||
if (stopped) return; // 卫语句:注销后不再跑
|
||||
for (const subs of deps) subs.delete(run); // 清上一轮订阅:条件分支换掉后的旧依赖不该再唤它
|
||||
deps.clear();
|
||||
const prev = active;
|
||||
const prevDeps = activeDeps;
|
||||
active = run;
|
||||
activeDeps = deps;
|
||||
try {
|
||||
fn();
|
||||
} finally {
|
||||
active = prev;
|
||||
activeDeps = prevDeps;
|
||||
}
|
||||
};
|
||||
run();
|
||||
return () => {
|
||||
/* 演示级实现:不做依赖清理 */
|
||||
stopped = true;
|
||||
for (const subs of deps) subs.delete(run); // 真摘订阅:否则卸载后的组件仍会被信号唤醒
|
||||
deps.clear();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user