diff --git a/packages/reactivity/src/computed.ts b/packages/reactivity/src/computed.ts index ef79bb1..0306064 100644 --- a/packages/reactivity/src/computed.ts +++ b/packages/reactivity/src/computed.ts @@ -1,20 +1,30 @@ import { isFunction } from '@vue/shared' import { Dep } from './dep' import { ReactiveEffect } from './effect' -import { trackRefValue } from './ref' +import { trackRefValue, triggerRefValue } from './ref' export class ComputedRefImpl { public dep?: Dep = undefined private _value!: T public readonly effect: ReactiveEffect public readonly __v_isRef = true + + public _dirty = true //为true时,需要重新执行run方法, 也就是说数据脏了的意思 constructor(getter) { - this.effect = new ReactiveEffect(getter) + this.effect = new ReactiveEffect(getter, () => { + if (!this._dirty) { + this._dirty = true + triggerRefValue(this) + } + }) this.effect.computed = this } get value() { - trackRefValue(this) //触发依赖 - this._value = this.effect.run() + trackRefValue(this) + if (this._dirty) { + this._dirty = false + this._value = this.effect.run() + } return this._value } } diff --git a/packages/reactivity/src/effect.ts b/packages/reactivity/src/effect.ts index 510db96..5c926f7 100644 --- a/packages/reactivity/src/effect.ts +++ b/packages/reactivity/src/effect.ts @@ -1,6 +1,7 @@ import { createDep, Dep } from './dep' import { isArray } from '@vue/shared' import { ComputedRefImpl } from './computed' +export type EffectScheduler = (...args: any[]) => any type KeyToDepMap = Map /** @@ -21,7 +22,10 @@ export let activeEffect: ReactiveEffect | undefined export class ReactiveEffect { computed?: ComputedRefImpl - constructor(public fn: () => T) {} + constructor( + public fn: () => T, + public scheduler: EffectScheduler | null = null + ) {} run() { //当前被激活的effect实例 activeEffect = this @@ -78,14 +82,26 @@ export function trigger(target: object, key: unknown, newValue: unknown) { } /** - * 依次触发dep中保存的依赖 + * 触发dep中保存的依赖 * @param dep */ export function triggerEffects(dep: Dep) { + //把dep构建为一个数组 const effects = isArray(dep) ? dep : [...dep] - //依次触发依赖 + //不再依次触发依赖 + // for (const effect of effects) { + // triggerEffect(effect) + // } + //而是先触发所有的计算属性依赖, 再触发所有的非计算属性依赖 for (const effect of effects) { - triggerEffect(effect) + if (effect.computed) { + triggerEffect(effect) + } + } + for (const effect of effects) { + if (!effect.computed) { + triggerEffect(effect) + } } } @@ -94,5 +110,9 @@ export function triggerEffects(dep: Dep) { * @param effect */ export function triggerEffect(effect: ReactiveEffect) { - effect.run() + if (effect.scheduler) { + effect.scheduler() + } else { + effect.run() + } } diff --git a/packages/vue/examples/reactivity/computed-cache.html b/packages/vue/examples/reactivity/computed-cache.html new file mode 100644 index 0000000..96cb2d4 --- /dev/null +++ b/packages/vue/examples/reactivity/computed-cache.html @@ -0,0 +1,28 @@ + + + + + Document + + + +
+ + + \ No newline at end of file