Skip to content

Commit

Permalink
perf(reactivity): optimize effect/effectScope active state tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jan 28, 2022
1 parent 6b68898 commit 2993a24
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 34 deletions.
54 changes: 30 additions & 24 deletions packages/reactivity/src/effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ export type DebuggerEventExtraInfo = {
oldTarget?: Map<any, any> | Set<any>
}

const effectStack: ReactiveEffect[] = []
let activeEffect: ReactiveEffect | undefined

export const ITERATE_KEY = Symbol(__DEV__ ? 'iterate' : '')
Expand All @@ -54,6 +53,7 @@ export const MAP_KEY_ITERATE_KEY = Symbol(__DEV__ ? 'Map key iterate' : '')
export class ReactiveEffect<T = any> {
active = true
deps: Dep[] = []
parent: ReactiveEffect | undefined = undefined

/**
* Can be attached after creation
Expand All @@ -74,7 +74,7 @@ export class ReactiveEffect<T = any> {
constructor(
public fn: () => T,
public scheduler: EffectScheduler | null = null,
scope?: EffectScope | null
scope?: EffectScope
) {
recordEffectScope(this, scope)
}
Expand All @@ -83,31 +83,37 @@ export class ReactiveEffect<T = any> {
if (!this.active) {
return this.fn()
}
if (!effectStack.length || !effectStack.includes(this)) {
try {
effectStack.push((activeEffect = this))
enableTracking()
let parent: ReactiveEffect | undefined = activeEffect
let lastShouldTrack = shouldTrack
while (parent) {
if (parent === this) {
return
}
parent = parent.parent
}
try {
this.parent = activeEffect
activeEffect = this
shouldTrack = true

trackOpBit = 1 << ++effectTrackDepth
trackOpBit = 1 << ++effectTrackDepth

if (effectTrackDepth <= maxMarkerBits) {
initDepMarkers(this)
} else {
cleanupEffect(this)
}
return this.fn()
} finally {
if (effectTrackDepth <= maxMarkerBits) {
finalizeDepMarkers(this)
}
if (effectTrackDepth <= maxMarkerBits) {
initDepMarkers(this)
} else {
cleanupEffect(this)
}
return this.fn()
} finally {
if (effectTrackDepth <= maxMarkerBits) {
finalizeDepMarkers(this)
}

trackOpBit = 1 << --effectTrackDepth
trackOpBit = 1 << --effectTrackDepth

resetTracking()
effectStack.pop()
const n = effectStack.length
activeEffect = n > 0 ? effectStack[n - 1] : undefined
}
activeEffect = this.parent
shouldTrack = lastShouldTrack
this.parent = undefined
}
}

Expand Down Expand Up @@ -214,7 +220,7 @@ export function track(target: object, type: TrackOpTypes, key: unknown) {
}

export function isTracking() {
return shouldTrack && activeEffect !== undefined
return shouldTrack && !!activeEffect
}

export function trackEffects(
Expand Down
21 changes: 12 additions & 9 deletions packages/reactivity/src/effectScope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { ReactiveEffect } from './effect'
import { warn } from './warning'

let activeEffectScope: EffectScope | undefined
const effectScopeStack: EffectScope[] = []

export class EffectScope {
active = true
Expand Down Expand Up @@ -42,24 +41,29 @@ export class EffectScope {

on() {
if (this.active) {
effectScopeStack.push(this)
activeEffectScope = this
}
}

off() {
if (this.active) {
effectScopeStack.pop()
activeEffectScope = effectScopeStack[effectScopeStack.length - 1]
activeEffectScope = this.parent
}
}

stop(fromParent?: boolean) {
if (this.active) {
this.effects.forEach(e => e.stop())
this.cleanups.forEach(cleanup => cleanup())
let i, l
for (i = 0, l = this.effects.length; i < l; i++) {
this.effects[i].stop()
}
for (i = 0, l = this.cleanups.length; i < l; i++) {
this.cleanups[i]()
}
if (this.scopes) {
this.scopes.forEach(e => e.stop(true))
for (i = 0, l = this.scopes.length; i < l; i++) {
this.scopes[i].stop(true)
}
}
// nested scope, dereference from parent to avoid memory leaks
if (this.parent && !fromParent) {
Expand All @@ -81,9 +85,8 @@ export function effectScope(detached?: boolean) {

export function recordEffectScope(
effect: ReactiveEffect,
scope?: EffectScope | null
scope: EffectScope | undefined = activeEffectScope
) {
scope = scope || activeEffectScope
if (scope && scope.active) {
scope.effects.push(effect)
}
Expand Down
2 changes: 1 addition & 1 deletion packages/reactivity/src/ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function triggerRefValue(ref: RefBase<any>, newVal?: any) {

export function isRef<T>(r: Ref<T> | unknown): r is Ref<T>
export function isRef(r: any): r is Ref {
return Boolean(r && r.__v_isRef === true)
return !!(r && r.__v_isRef === true)
}

export function ref<T extends object>(
Expand Down

0 comments on commit 2993a24

Please sign in to comment.