实现 effect 的 stop 性能
//effect.spec
it('stop', () => {
let dummy
const obj = reactive({prop: 1})
const runner = effect(() => {dummy = obj.prop})
obj.prop = 2
expect(dummy).toBe(2)
// stop 一个 runner 之后
stop(runner)
obj.prop++
// 依赖再次更新,过后传入的 effect 则不会从新执行
expect(dummy).toBe(2)
// runner 不受到影响
runner()
expect(dummy).toBe(3)
})
//effect.ts
let activeEffect
let shouldTrack
const targetMap = new WeakMap()
class ReactiveEffect{
private _fn
deps=[]
active= true
constructor(fn,public scheduler?){this._fn = fn}
run(){if (!this.active) {return this._fn();
}
// 应该收集
shouldTrack = true;
activeEffect = this;
const r = this._fn();
// 重置
shouldTrack = false;
return r;
}
stop(){if (this.active) {cleanupEffect(this)
}
this.active = false
}
}
function cleanupEffect(effect){effect.deps.forEach((dep: any) => {dep.delete(effect)
})
}
export function track(target, key){let depsMap = targetMap.get(target)
if(!depsMap){depsMap = new Map()
targetMap.set(target,depsMap)
}
let dep = depsMap.get(key)
if(!dep){dep = new Set()
depsMap.set(key,dep)
}
// 判断是否应该收集,stop 过的 shouldTrack 为 false
if(activeEffect&&shouldTrack){activeEffect.deps.push(dep)
dep.add(activeEffect)
}
}
export function trigger(target, key){let depsMap = targetMap.get(target)
let deps = depsMap.get(key)
for(const effect of deps){if(effect.scheduler){effect.scheduler()
}else{effect.run()
}
}
}
export function effect(fn,option:any={}){const _effect = new ReactiveEffect(fn,option.scheduler)
_effect.run();
let runner:any = _effect.run.bind(_effect)
runner.effect = _effect
return runner
}
export function stop(runner){runner.effect.stop()
}