Vue3源码系列——computed

343 阅读1分钟

看文章前,请先看reactive和ref的文章。

如何使用

setup() {
    const refMsg2 = ref('2222')
    const computed1 = computed(() => refMsg2.value+'2111111')
    return () => h("div", {}, [h("p", {}, `${computed1.value}-apiInject-${refMsg2.value}`)]);
}

computed源码

  1. computed执行new ComputedRefImpl,我们看ComputedRefImpl
  2. _dirty用来标记数据是否需要更新,实现缓存作用,_dirty=true证明数据是脏的,被使用时需要重新执行一次。
  3. dep收集依赖
  4. ReactiveEffect的作用参考前几节,重点看两个参数
class ReactiveEffect {
    constructor(fn, scheduler) {
        this.fn = fn;
        this.scheduler = scheduler;
        this.active = true;
        this.deps = [];
    }
    run() {
        if (!this.active) {
            return this.fn();
        }
        shouldTrack = true;
        activeEffect = this;
        const result = this.fn();
        shouldTrack = false;
        activeEffect = undefined;
        return result;
    }
    ...
}
  1. 第一个参数getter使用时传入的函数
  2. 第二个参数用来触发依赖
function computed(getter) {
    return new ComputedRefImpl(getter);
}

class ComputedRefImpl {
    constructor(getter) {
        this._dirty = true;
        this.dep = createDep();
        this.effect = new ReactiveEffect(getter, () => {
            if (this._dirty)
                return;
            this._dirty = true;
            triggerRefValue(this);
        });
    }
    get value() {
        trackRefValue(this);
        if (this._dirty) {
            this._dirty = false;
            this._value = this.effect.run();
        }
        return this._value;
    }
}

当setup中使用了computed1.value

  1. trackRefValue依赖收集
  2. this._dirty是true时,则this._value = this.effect.run();run就是使用时传入的函数,同时this._dirty=false;this._dirty是false时,return this._value;
  3. run执行时用到了哪些响应式数据就会把compute的实例,也放进对应数据的deps中;
function triggerEffects(dep) {
    for (const effect of dep) {
        if (effect.scheduler) {
            effect.scheduler();
        }
        else {
            effect.run();
        }
    }
}
  1. 当computed用的数据,其中一个改变时,就会触发它所有的依赖,computed的实例是有scheduler的,执行scheduler。
  2. 执行scheduler就是ReactiveEffect第二个参数,computed的依赖变了则修改标记this._dirty = true,同时触发triggerRefValue(this);