uni-h5-vue里面EffectScope解析

25 阅读1分钟

EffectScope(effectScope)是 Vue 3 响应式系统的“作用域容器”,用来把在某段代码里创建的副作用(watch/watchEffect/computed 内部的 ReactiveEffect)归组管理,便于一次性停止,防止内存泄漏。

effects cleanups parent


const scope = effectScope()

class EffectScope {
  constructor(detached = false) {
    this.detached = detached;
    /**
     * @internal
     */
    this._active = true;
    /**
     * @internal
     */
    this.effects = [];
    /**
     * @internal
     */
    this.cleanups = [];
    this.parent = activeEffectScope;
    if (!detached && activeEffectScope) {
      this.index = (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
        this
      ) - 1;
    }
  }
  
  run(fn) {
    if (this._active) {
      const currentEffectScope = activeEffectScope;
      try {
        activeEffectScope = this;
        return fn();
        
            scope.run(()=>{
               const count = ref(0)
              const doubled = computed(() => count.value * 2)

              watchEffect(() => {
                console.log('doubled:', doubled.value)
              })
            })
        
      } finally {
        activeEffectScope = currentEffectScope;
      }
    } else if (!!(process.env.NODE_ENV !== "production")) {
      warn$2(`cannot run an inactive effect scope.`);
    }
  }

scope.stop()

 stop(fromParent) {
    if (this._active) {
      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) {
        for (i = 0, l = this.scopes.length; i < l; i++) {
          this.scopes[i].stop(true);
        }
      }
      if (!this.detached && this.parent && !fromParent) {
        const last = this.parent.scopes.pop();
        if (last && last !== this) {
          this.parent.scopes[this.index] = last;
          last.index = this.index;
        }
      }
      this.parent = void 0;
      this._active = false;
    }
  }
  
   if (getCurrentScope()) {
    onScopeDispose(() => scope.stop())
  }
  
  function getCurrentScope() {
  return activeEffectScope;
}
function onScopeDispose(fn) {
  if (activeEffectScope) {
    activeEffectScope.cleanups.push(fn);
  } else if (!!(process.env.NODE_ENV !== "production")) {
    warn$2(
      `onScopeDispose() is called when there is no active effect scope to be associated with.`
    );
  }
}


function recordEffectScope(effect, scope = activeEffectScope) {
  if (scope && scope.active) {
    scope.effects.push(effect);
  }
}

  1. effectScope初始化
     detached _active effects cleanups parent index
  2. 父子effectScope 转交控制权限 收集一组副作用
     computed watch watchEffect 等ReactiveEffec 会调用 recordEffectScope
  3. 父effectScope 控制effectScope子清除
     onScopeDispose 父effectScope清理函数添加子effectScope stop
  4. effectScope清除
     _active字段保护 effects停止 cleanups执行 触发子scopes递归清空 主动清空采取swap-with-last + pop