VUE 3.0源码之effect

7 篇文章 0 订阅
6 篇文章 0 订阅

effect方法主要用于处理函数的响应式,可用于计算属性和watchEffect等功能,通过触发函数中响应式变量的proxyget方法实现将自身加入到proxydeps中,实现与proxy关联,也可以将其他依赖收集到自己的deps中

1. effect

创建一个effect函数,如果不是lazy创建时会先调用一遍,这样可以调用相关get并将effect加入相关proxy的deps中

function effect<T = any>(
  fn: () => T,
  options: ReactiveEffectOptions = EMPTY_OBJ
): ReactiveEffect<T> {
  if (isEffect(fn)) { // 如果已经是effect则将原函数取出来
    fn = fn.raw
  }
  const effect = createReactiveEffect(fn, options)
  if (!options.lazy) { // 如果不是lazy则先调用一遍effect,这个时候可以触发相关proxy的get
    effect()
  }
  return effect
}
2. createReactiveEffect

当调用effect时会创建一个函数,该函数主要用于收集依赖和充当watcher。当生成的函数被调用时,先判断active属性,如果false则不会被收集依赖;接着将自身添加到effectStack中和将activeEffect改为自身,当调用fn时触发fn中响应式变量的get,这时get会把effect添加到响应式变量的依赖中;最后从effectStack去除并重新赋值activeEffect。

function createReactiveEffect<T = any>(
  fn: (...args: any[]) => T,
  options: ReactiveEffectOptions
): ReactiveEffect<T> {
  const effect = function reactiveEffect(...args: unknown[]): unknown {
    if (!effect.active) {
      return options.scheduler ? undefined : fn(...args)
    }
    if (!effectStack.includes(effect)) {
      // 将effect从target.key的依赖中删除,并将自身的deps重置
      // 这里每次都要清除一次,可能是为了防止fn中有条件判断导致响应式数据变化而导致依赖没有及时变化
      cleanup(effect)
      try {
        // 将标记置为可收集依赖
        enableTracking()
        effectStack.push(effect)
        // 将effect赋给activeEffect,会在reactive的getter方法中调用track放入reactive的deps中
        activeEffect = effect
        // 这里先调用一遍,触发getter
        return fn(...args)
      } finally {
        // 最后要把处理好的effect从队列中去掉
        effectStack.pop()
        resetTracking()
        activeEffect = effectStack[effectStack.length - 1]
      }
    }
  } as ReactiveEffect
  effect._isEffect = true
  effect.active = true
  effect.raw = fn
  effect.deps = [] // 这里放置和effect相关的deps
  effect.options = options
  return effect
}
3. track

这里主要用于收集依赖

function track(target: object, type: TrackOpTypes, key: unknown) {
  if (!shouldTrack || activeEffect === undefined) {
    return
  }
  // 根据target将一个Map放入targetMap中
  let depsMap = targetMap.get(target)
  if (depsMap === void 0) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key)
  if (dep === void 0) {
  	// 用Set存储deps
    depsMap.set(key, (dep = new Set()))
  }
  if (!dep.has(activeEffect)) {
  	// 将effect添加到target.key的依赖中
    dep.add(activeEffect)
    // 将target.key的依赖收入到effect中,用于cleanup中使用
    activeEffect.deps.push(dep)
    if (__DEV__ && activeEffect.options.onTrack) {
      activeEffect.options.onTrack({
        effect: activeEffect,
        target,
        type,
        key
      })
    }
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值