perf(reactivity): optimize effect/effectScope active state tracking
This commit is contained in:
		
							parent
							
								
									6b6889852f
								
							
						
					
					
						commit
						2993a24618
					
				@ -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' : '')
 | 
			
		||||
@ -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
 | 
			
		||||
@ -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)
 | 
			
		||||
  }
 | 
			
		||||
@ -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()
 | 
			
		||||
 | 
			
		||||
        trackOpBit = 1 << ++effectTrackDepth
 | 
			
		||||
 | 
			
		||||
        if (effectTrackDepth <= maxMarkerBits) {
 | 
			
		||||
          initDepMarkers(this)
 | 
			
		||||
        } else {
 | 
			
		||||
          cleanupEffect(this)
 | 
			
		||||
        }
 | 
			
		||||
        return this.fn()
 | 
			
		||||
      } finally {
 | 
			
		||||
        if (effectTrackDepth <= maxMarkerBits) {
 | 
			
		||||
          finalizeDepMarkers(this)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        trackOpBit = 1 << --effectTrackDepth
 | 
			
		||||
 | 
			
		||||
        resetTracking()
 | 
			
		||||
        effectStack.pop()
 | 
			
		||||
        const n = effectStack.length
 | 
			
		||||
        activeEffect = n > 0 ? effectStack[n - 1] : undefined
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
      if (effectTrackDepth <= maxMarkerBits) {
 | 
			
		||||
        initDepMarkers(this)
 | 
			
		||||
      } else {
 | 
			
		||||
        cleanupEffect(this)
 | 
			
		||||
      }
 | 
			
		||||
      return this.fn()
 | 
			
		||||
    } finally {
 | 
			
		||||
      if (effectTrackDepth <= maxMarkerBits) {
 | 
			
		||||
        finalizeDepMarkers(this)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      trackOpBit = 1 << --effectTrackDepth
 | 
			
		||||
 | 
			
		||||
      activeEffect = this.parent
 | 
			
		||||
      shouldTrack = lastShouldTrack
 | 
			
		||||
      this.parent = undefined
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -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(
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@ import { ReactiveEffect } from './effect'
 | 
			
		||||
import { warn } from './warning'
 | 
			
		||||
 | 
			
		||||
let activeEffectScope: EffectScope | undefined
 | 
			
		||||
const effectScopeStack: EffectScope[] = []
 | 
			
		||||
 | 
			
		||||
export class EffectScope {
 | 
			
		||||
  active = true
 | 
			
		||||
@ -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) {
 | 
			
		||||
@ -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)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -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>(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user