今天继续总结学习Vue3.0的基本原理。computed(), 计算属性,在vue3.0中computed可以传入一个getter函数也可以传入getter与setter两个函数。
在computed模块中,首先处理处理用户传入的对象,在接收对象时分为一个参数与两个参数的情况,最终返回一个computed对象,在处理传入的对象时其实是调用effect模块,让其成为响应式的数据,所以computed也是另一种形式的effect。因此,在effect模块中要加入对computed类型的处理,分而治之,并且computed优先于一般的effect执行。大概思路就是这样,直接上代码:
export function computed(getterOrOptions) {
 let getter; //接收传入的参数
 let setter;
 if (isFunction(getterOrOptions)) { //isFunction是自定义的工具函数
    getter = getterOrOptions;
    setter = ()=>{}
  } else {
    getter = getterOrOptions.get;
    setter = getterOrOptions.set;
  }
 let dirty = true;//缓存机制的标志 控制是否触发依赖,达到缓存效果
 let computed;
 let runner = effect(getter, { //调用effect
    lazy: true, //首次不执行
    computed: true,//计算属性标识
    scheduler: ()=>{ //在有新的依赖触发时effect负责执行
 if (!dirty) {
        dirty = true;//依赖值变化后  没有缓存数据了
        trigger(computed,TriggerOpTypes.SET,'value') //触发依赖
      }
    }
  })
 let value;
  computed = {
    get value() {
 if (dirty) {  //多次取值 不会重复执行effect
        value = runner();
        dirty = false;
        track(computed,TriggerOpTypes.GET,'value')//收集计算结果的依赖,使其成为响应式数据
      }
 return value;
    },
    set value(newValue) {
      setter(newValue)
    }
  }
 return computed;
}
effect中的配合
export function trigger(target, type, key, value, oldValue) {
 //获取当前对应的map
 const depsMap = targetMap.get(target); 
 if (!depsMap) {
 return; //说明没有被收集过依赖
  }
 //计算属性优先于effect执行
 const effects = new Set(); //装普通effect
 const computedRunners = new Set(); //装计算属性的effect
 //具体执行effect集合的方法
 // const run = (effect) => {
 //   if (effect) {
 //     effect.forEach(effect => effect())
 //   }
 // }
 const run = (effect) => {
 if (effect.options.scheduler) {
      effect.options.scheduler()
    } else {
      effect();
    }
  }
 let add = (effectsToAdd)=>{
 if (effectsToAdd) {
      effectsToAdd.forEach(effect => {
 if (effect.options.computed) {
          computedRunners.add(effect)
        } else {
          effects.add(effect)
        }
      })
    }
  }
 if (key !== null) { 
    add(depsMap.get(key));
  }
 if (type === TriggerOpTypes.ADD) {  
    add(depsMap.get(Array.isArray(target) ? 'length' : ''))
  }
  computedRunners.forEach(run)
  effects.forEach(run)
}
在触发effect中,增加了两个存储computed和effect的集合,通过add方法所有的依赖map中的effect分类,最后分开执行;
computed的实现基础还是effect,可以理解为effect的一种变形。