runner
effect.spec.ts
it("return runner when call effect", () => {
let foo = 10;
const runner = effect(() => {
foo++;
return "return-effect";
});
expect(foo).toBe(11);
const r = runner();
expect(foo).toBe(12);
expect(r).toBe("return-effect");
});
effect.ts
// 当前活跃的effect实例
let activeEffect;
class Effect {
private _fn: any;
constructor(fn) {
this._fn = fn;
}
// 执行effect接收的fn
run() {
activeEffect = this;
// return 执行结果
return this._fn();
}
}
// 收集依赖
const targetMap = new Map(); // 所有的依赖,触发依赖的时候会从这里面取
export function track(target, key) {
let depMap = targetMap.get(target);
if (!depMap) {
depMap = new Map();
targetMap.set(target, depMap);
}
let dep = depMap.get(key);
if (!dep) {
dep = new Set();
depMap.set(key, dep);
}
dep.add(activeEffect);
}
// 触发依赖
export function trigger(target, key) {
let depMap = targetMap.get(target);
let dep = depMap.get(key);
for (const effect of dep) {
effect.run();
}
}
export function effect(fn) {
const _effect = new Effect(fn);
_effect.run();
// 实现runner
const runner = _effect.run.bind(_effect);
return runner;
}
scheduler
effect.spec.ts
it("scheduler", () => {
let dummy;
let run: any;
const scheduler = jest.fn(() => {
run = runner;
});
const obj = reactive({ foo: 1 });
const runner = effect(
() => {
dummy = obj.foo;
},
{ scheduler }
);
expect(scheduler).not.toHaveBeenCalled();
expect(dummy).toBe(1);
obj.foo++;
expect(scheduler).toHaveBeenCalledTimes(1);
expect(dummy).toBe(1);
run();
expect(dummy).toBe(2);
});
effect.ts
let activeEffect;
class Effect {
private _fn: any;
scheduler: any;
constructor(fn) {
this._fn = fn;
}
run() {
activeEffect = this;
return this._fn();
}
}
const targetMap = new Map();
export function track(target, key) {
let depMap = targetMap.get(target);
if (!depMap) {
depMap = new Map();
targetMap.set(target, depMap);
}
let dep = depMap.get(key);
if (!dep) {
dep = new Set();
depMap.set(key, dep);
}
dep.add(activeEffect);
}
export function trigger(target, key) {
let depMap = targetMap.get(target);
let dep = depMap.get(key);
for (const effect of dep) {
if (effect.scheduler) {
effect.scheduler();
return;
}
effect.run();
}
}
export function effect(fn, option: any = {}) {
const _effect = new Effect(fn);
_effect.scheduler = option.scheduler;
_effect.run();
const runner = _effect.run.bind(_effect);
return runner;
}