Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(effect): refactorings to improve performance, reduce memory usage #2345

Closed
wants to merge 11 commits into from
41 changes: 21 additions & 20 deletions packages/reactivity/__tests__/effect.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -423,8 +423,8 @@ describe('reactivity/effect', () => {
}
const effect1 = effect(greet)
const effect2 = effect(greet)
expect(typeof effect1).toBe('function')
expect(typeof effect2).toBe('function')
expect(typeof effect1).toBe('object')
expect(typeof effect2).toBe('object')
expect(effect1).not.toBe(greet)
expect(effect1).not.toBe(effect2)
})
Expand Down Expand Up @@ -460,10 +460,10 @@ describe('reactivity/effect', () => {
})

expect(dummy).toBe('other')
runner()
runner.run()
expect(dummy).toBe('other')
run = true
runner()
runner.run()
expect(dummy).toBe('value')
obj.prop = 'World'
expect(dummy).toBe('World')
Expand All @@ -490,7 +490,7 @@ describe('reactivity/effect', () => {

it('should not double wrap if the passed function is a effect', () => {
const runner = effect(() => {})
const otherRunner = effect(runner)
const otherRunner = effect(runner.func)
expect(runner).not.toBe(otherRunner)
expect(runner.raw).toBe(otherRunner.raw)
})
Expand Down Expand Up @@ -520,7 +520,7 @@ describe('reactivity/effect', () => {
const childeffect = effect(childSpy)
const parentSpy = jest.fn(() => {
dummy.num2 = nums.num2
childeffect()
childeffect.run()
dummy.num3 = nums.num3
})
effect(parentSpy)
Expand Down Expand Up @@ -578,10 +578,10 @@ describe('reactivity/effect', () => {
it('lazy', () => {
const obj = reactive({ foo: 1 })
let dummy
const runner = effect(() => (dummy = obj.foo), { lazy: true })
const runner = effect(() => (dummy = obj.foo), undefined, false, true)
expect(dummy).toBe(undefined)

expect(runner()).toBe(1)
expect(runner.run()).toBe(1)
expect(dummy).toBe(1)
obj.foo = 2
expect(dummy).toBe(2)
Expand All @@ -593,12 +593,9 @@ describe('reactivity/effect', () => {
runner = _runner
})
const obj = reactive({ foo: 1 })
effect(
() => {
dummy = obj.foo
},
{ scheduler }
)
effect(() => {
dummy = obj.foo
}, scheduler)
expect(scheduler).not.toHaveBeenCalled()
expect(dummy).toBe(1)
// should be called on first trigger
Expand All @@ -625,6 +622,9 @@ describe('reactivity/effect', () => {
dummy = 'bar' in obj
dummy = Object.keys(obj)
},
undefined,
false,
false,
{ onTrack }
)
expect(dummy).toEqual(['foo', 'bar'])
Expand Down Expand Up @@ -662,6 +662,9 @@ describe('reactivity/effect', () => {
() => {
dummy = obj.foo
},
undefined,
false,
false,
{ onTrigger }
)

Expand Down Expand Up @@ -703,7 +706,7 @@ describe('reactivity/effect', () => {
expect(dummy).toBe(2)

// stopped effect should still be manually callable
runner()
runner.run()
expect(dummy).toBe(3)
})

Expand All @@ -715,9 +718,7 @@ describe('reactivity/effect', () => {
() => {
dummy = obj.prop
},
{
scheduler: e => queue.push(e)
}
e => queue.push(e)
)
obj.prop = 2
expect(dummy).toBe(1)
Expand All @@ -731,7 +732,7 @@ describe('reactivity/effect', () => {

it('events: onStop', () => {
const onStop = jest.fn()
const runner = effect(() => {}, {
const runner = effect(() => {}, undefined, false, false, {
onStop
})

Expand All @@ -752,7 +753,7 @@ describe('reactivity/effect', () => {
// observed value in inner stopped effect
// will track outer effect as an dependency
effect(() => {
runner()
runner.run()
})
expect(dummy).toBe(2)

Expand Down
6 changes: 6 additions & 0 deletions packages/reactivity/__tests__/shallowReactive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ describe('shallowReactive', () => {
() => {
a = Array.from(shallowSet)
},
undefined,
false,
false,
{
onTrack: onTrackFn
}
Expand Down Expand Up @@ -113,6 +116,9 @@ describe('shallowReactive', () => {
() => {
a = Array.from(shallowArray)
},
undefined,
false,
false,
{
onTrack: onTrackFn
}
Expand Down
31 changes: 17 additions & 14 deletions packages/reactivity/src/computed.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { effect, ReactiveEffect, trigger, track } from './effect'
import { TriggerOpTypes, TrackOpTypes } from './operations'
import { Ref } from './ref'
import { effect, ReactiveEffect } from './effect'
import { Ref, trackRefValue, triggerRefValue } from './ref'
import { isFunction, NOOP } from '@vue/shared'
import { ReactiveFlags, toRaw } from './reactive'
import { ReactiveFlags } from './reactive'

export interface ComputedRef<T = any> extends WritableComputedRef<T> {
readonly value: T
Expand All @@ -24,35 +23,36 @@ class ComputedRefImpl<T> {
private _value!: T
private _dirty = true

public readonly effect: ReactiveEffect<T>
public readonly effect: ReactiveEffect<T>;

public readonly __v_isRef = true;
public readonly [ReactiveFlags.IS_READONLY]: boolean

constructor(
getter: ComputedGetter<T>,
private readonly _setter: ComputedSetter<T>,
isReadonly: boolean
) {
this.effect = effect(getter, {
lazy: true,
scheduler: () => {
this.effect = effect(
getter,
() => {
if (!this._dirty) {
this._dirty = true
trigger(toRaw(this), TriggerOpTypes.SET, 'value')
triggerRefValue(this)
}
}
})
},
false,
true
)

this[ReactiveFlags.IS_READONLY] = isReadonly
}

get value() {
if (this._dirty) {
this._value = this.effect()
this._value = this.effect.run() as T
this._dirty = false
}
track(toRaw(this), TrackOpTypes.GET, 'value')
trackRefValue(this)
return this._value
}

Expand All @@ -61,6 +61,9 @@ class ComputedRefImpl<T> {
}
}

ComputedRefImpl.prototype.__v_isRef = true
interface ComputedRefImpl<T> extends Ref<T> {}

export function computed<T>(getter: ComputedGetter<T>): ComputedRef<T>
export function computed<T>(
options: WritableComputedOptions<T>
Expand Down
Loading