vue3 Reactivity是一个响应式独立的包,其中主要分成几个部分,比如handlers、porxy、effect、dep。

Handlers

  1. function createGetter(isReadonly = false, shallow = false) {
  2. return function get(target: Target, key: string | symbol, receiver: object) {
  3. // 如果已经被代理过就返回
  4. if (key === ReactiveFlags.IS_REACTIVE) {
  5. return !isReadonly
  6. } else if (key === ReactiveFlags.IS_READONLY) {
  7. return isReadonly
  8. } else if (key === ReactiveFlags.IS_SHALLOW) {
  9. return shallow
  10. } else if (
  11. key === ReactiveFlags.RAW &&
  12. receiver ===
  13. (isReadonly
  14. ? shallow
  15. ? shallowReadonlyMap
  16. : readonlyMap
  17. : shallow
  18. ? shallowReactiveMap
  19. : reactiveMap
  20. ).get(target)
  21. ) {
  22. return target
  23. }
  24. const targetIsArray = isArray(target)
  25. if (!isReadonly && targetIsArray && hasOwn(arrayInstrumentations, key)) {
  26. return Reflect.get(arrayInstrumentations, key, receiver)
  27. }
  28. // 获取值
  29. const res = Reflect.get(target, key, receiver)
  30. if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
  31. return res
  32. }
  33. // 不是只读的收集依赖
  34. if (!isReadonly) {
  35. track(target, TrackOpTypes.GET, key)
  36. }
  37. // 浅层的,直接返回
  38. if (shallow) {
  39. return res
  40. }
  41. // 处理ref
  42. if (isRef(res)) {
  43. // ref unwrapping - does not apply for Array + integer key.
  44. const shouldUnwrap = !targetIsArray || !isIntegerKey(key)
  45. return shouldUnwrap ? res.value : res
  46. }
  47. // 递归观测reactive数据
  48. if (isObject(res)) {
  49. return isReadonly ? readonly(res) : reactive(res)
  50. }
  51. return res
  52. }
  53. }
  54. function createSetter(shallow = false) {
  55. return function set(
  56. target: object,
  57. key: string | symbol,
  58. value: unknown,
  59. receiver: object
  60. ): boolean {
  61. let oldValue = (target as any)[key]
  62. // 如果旧值是只读的,set函数需要返回一个bool值
  63. if (isReadonly(oldValue) && isRef(oldValue) && !isRef(value)) {
  64. return false
  65. }
  66. // 处理浅层和ref
  67. if (!shallow && !isReadonly(value)) {
  68. if (!isShallow(value)) {
  69. value = toRaw(value)
  70. oldValue = toRaw(oldValue)
  71. }
  72. if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
  73. oldValue.value = value
  74. return true
  75. }
  76. } else {
  77. }
  78. const hadKey =
  79. isArray(target) && isIntegerKey(key)
  80. ? Number(key) < target.length
  81. : hasOwn(target, key)
  82. // 设置reactive对象的值
  83. const result = Reflect.set(target, key, value, receiver)
  84. // 数据已经修改,触发更新, set时trigger, get时track
  85. if (target === toRaw(receiver)) {
  86. if (!hadKey) {
  87. trigger(target, TriggerOpTypes.ADD, key, value)
  88. } else if (hasChanged(value, oldValue)) {
  89. trigger(target, TriggerOpTypes.SET, key, value, oldValue)
  90. }
  91. }
  92. return result
  93. }
  94. }

对于深层handlers,在设置和获取时会多一步递归的操作


function get(
  target: MapTypes,
  key: unknown,
  isReadonly = false,
  isShallow = false
) {

  target = (target as any)[ReactiveFlags.RAW]
  const rawTarget = toRaw(target)
  const rawKey = toRaw(key)
  if (key !== rawKey) {
    !isReadonly && track(rawTarget, TrackOpTypes.GET, key)
  }
  !isReadonly && track(rawTarget, TrackOpTypes.GET, rawKey)
  const { has } = getProto(rawTarget)
  const wrap = isShallow ? toShallow : isReadonly ? toReadonly : toReactive
  if (has.call(rawTarget, key)) {
    return wrap(target.get(key))
  } else if (has.call(rawTarget, rawKey)) {
    return wrap(target.get(rawKey))
  } else if (target !== rawTarget) {

    target.get(key)
  }
}


function set(this: MapTypes, key: unknown, value: unknown) {
  value = toRaw(value)
  const target = toRaw(this)
  const { has, get } = getProto(target)

  let hadKey = has.call(target, key)
  if (!hadKey) {
    key = toRaw(key)
    hadKey = has.call(target, key)
  } else if (__DEV__) {
    checkIdentityKeys(target, has, key)
  }

  const oldValue = get.call(target, key)
  target.set(key, value)
  if (!hadKey) {
    trigger(target, TriggerOpTypes.ADD, key, value)
  } else if (hasChanged(value, oldValue)) {
    trigger(target, TriggerOpTypes.SET, key, value, oldValue)
  }
  return this
}

对于深层和浅层的handlers并没有具体实现,而是两种混合在一起,通过不同的工厂函数的参数来决定的,但是在入口函数执行时,会得到具体的handlers来使用

colletionHanlders 主要用于Map,Set,WeakMap,WeakSet等强类型数据结构, 如果是Array、Object则使用baseHanlders

比如:


export function shallowReactive<T extends object>(
  target: T
): ShallowReactive<T> {
  return createReactiveObject(
    target,
    false,
    // 工厂函数的生成
    shallowReactiveHandlers,
    shallowCollectionHandlers,
    shallowReactiveMap
  )
}

Reactive

reactive函数在响应式流程中相当于,依赖触发的生成者,具体实现是通过不同的handler使用Proxy api代理

export function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
export function reactive(target: object) {
  // if trying to observe a readonly proxy, return the readonly version.
  if (isReadonly(target)) {
    return target
  }
  return createReactiveObject(
    target,
    false,
    mutableHandlers,
    mutableCollectionHandlers,
    reactiveMap
  )
}

export function shallowReactive<T extends object>(
  target: T
): ShallowReactive<T> {
  return createReactiveObject(
    target,
    false,
    shallowReactiveHandlers,
    shallowCollectionHandlers,
    shallowReactiveMap
  )
}

俩个reactive是代理函数,通过不同的handlers由createReactiveObject生成

Proxy

proxy 是响应式具有代表性的一环,就是通过原生的Proxy api来实现, 这一步做的就是对整个vue用到的状态做数据劫持


function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>,
  proxyMap: WeakMap<Target, any>
) {
  // 目标已经被代理过,直接返回
  if (
    target[ReactiveFlags.RAW] &&
    !(isReadonly && target[ReactiveFlags.IS_REACTIVE])
  ) {
    return target
  }

  const existingProxy = proxyMap.get(target)
  if (existingProxy) {
    return existingProxy
  }
  // 如果不是reactive支持的数据类型直接返回
   /*
  // 目前支持的数据类型
function targetTypeMap(rawType: string) {
  switch (rawType) {
    case 'Object':
    case 'Array':
      return TargetType.COMMON
    case 'Map':
    case 'Set':
    case 'WeakMap':
    case 'WeakSet':
      return TargetType.COLLECTION
    default:
      return TargetType.INVALID
  }
}
   */
  const targetType = getTargetType(target)
  if (targetType === TargetType.INVALID) {
    return target
  }
    // 生成代理, 对于set,map使用collectionHanlders
  const proxy = new Proxy(
    target,
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  )
  // 缓存代理的结果,并返回代理后的对象
  proxyMap.set(target, proxy)
  return proxy
}


// 对于readonly, 里面最重要的就是这句,不能重新设置
{
  set(target, key) {
    if (__DEV__) {
      console.warn(
        `Set operation on key "${String(key)}" failed: target is readonly.`,
        target
      )
    }
    return true
  }

}

Ref

ref可以是一个基本数据类型或者是复杂数据类型


class RefImpl<T> {
  private _value: T
  private _rawValue: T
  // 用于存储当前Ref值的effect, 也就是activeEffect
  public dep?: Dep = undefined
  public readonly __v_isRef = true

  constructor(value: T, public readonly __v_isShallow: boolean) {
    this._rawValue = __v_isShallow ? value : toRaw(value)
    this._value = __v_isShallow ? value : toReactive(value)
  }

  get value() {
    // 收集依赖,并返回类内部对外不可见的的_value
    trackRefValue(this)
    return this._value
  }

  set value(newVal) {
    newVal = this.__v_isShallow ? newVal : toRaw(newVal)
    // 浅比较,也就是Object.is(), 如果有变化就触发更新
    if (hasChanged(newVal, this._rawValue)) {
      this._rawValue = newVal
      this._value = this.__v_isShallow ? newVal : toReactive(newVal)
      triggerRefValue(this, newVal)
    }
  }
}

class CustomRefImpl<T> {
  public dep?: Dep = undefined

  private readonly _get: ReturnType<CustomRefFactory<T>>['get']
  private readonly _set: ReturnType<CustomRefFactory<T>>['set']

  public readonly __v_isRef = true

  constructor(factory: CustomRefFactory<T>) {
    // 手动传入的factory
    const { get, set } = factory(
      () => trackRefValue(this),
      () => triggerRefValue(this)
    )
    this._get = get
    this._set = set
  }

  get value() {
    return this._get()
  }

  set value(newVal) {
    this._set(newVal)
  }
}


// 关于es6的Geeter、Setter函数
const ref = {
  get value() {
  },
  set value() {

  }
};

Effect


export class ReactiveEffect<T = any> {
  // active 判断是否可以正常工作的,比如实例调用了stop以后
  // active就是false,为false时会直接执行,但不会被触发依赖
  active = true
  // effect的依赖,key也有依赖,属于双向绑定的依赖
  deps: Dep[] = []
  // 用于前套effect的处理,之前是stack,现在变成了链表
  // stack -> [effetct, effect.parent  = prevEffect]
  // 在执行完毕回滚时,会调用parent为activeEffect
  parent: ReactiveEffect | undefined = undefined

  /**
   * 于computed的双向绑定
   */
  computed?: ComputedRefImpl<T>

  allowRecurse?: boolean

  onStop?: () => void
  // dev only
  onTrack?: (event: DebuggerEvent) => void
  // dev only
  onTrigger?: (event: DebuggerEvent) => void

  constructor(
    public fn: () => T,
    public scheduler: EffectScheduler | null = null,
    scope?: EffectScope
  ) {
      // 和scope的绑定
    recordEffectScope(this, scope)
  }

  run() {
    if (!this.active) {
      return this.fn()
    }
    // 模拟栈,用于前套, 但activeEffect并不一定是直接上层effect
    let parent: ReactiveEffect | undefined = activeEffect
    let lastShouldTrack = shouldTrack
    // 找到当前执行环境的effect,也就是自身处于链表的位置
    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 为当前执行的effect,执行时如果存在副作用
      // track时会被收集到map中
      activeEffect = this.parent
      shouldTrack = lastShouldTrack
      this.parent = undefined
    }
  }

  stop() {
    if (this.active) {
      cleanupEffect(this)
      if (this.onStop) {
        this.onStop()
      }
      this.active = false
    }
  }
}

// ### effectScope


let activeEffectScope: EffectScope | undefined

export class EffectScope {
  // 是否可工作
  active = true
  // 与effect的绑定
  effects: ReactiveEffect[] = []
  // 监听effectScopoe销毁时的函数数组
  cleanups: (() => void)[] = []
  // 嵌套使用的链表指针域
  parent: EffectScope | undefined
  scopes: EffectScope[] | undefined

  private index: number | undefined

  constructor(detached = false) {
    if (!detached && activeEffectScope) {
      this.parent = activeEffectScope
      this.index =
        (activeEffectScope.scopes || (activeEffectScope.scopes = [])).push(
          this
        ) - 1
    }
  }

  run<T>(fn: () => T): T | undefined {
    if (this.active) {
      try {
        activeEffectScope = this
        return fn()
      } finally {
        activeEffectScope = this.parent
      }
    } else if (__DEV__) {

      /*
        报错。 如果一个作用域已经被停职,再次执行会报错
       因为所有的effect已经被停止
       比如effect.active为false时,值执行函数,并不会处理依关系
      */
    }
  }

  on() {
    // 挂载链表
    activeEffectScope = this
  }

  off() {
    // 回滚链表
    activeEffectScope = this.parent
  }

  stop(fromParent?: boolean) {
    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)
        }
      }
      // nested scope, dereference from parent to avoid memory leaks
      if (this.parent && !fromParent) {
        // optimized O(1) removal
        const last = this.parent.scopes!.pop()
        if (last && last !== this) {
          this.parent.scopes![this.index!] = last
          last.index = this.index!
        }
      }
      this.active = false
    }
  }
}

export function recordEffectScope(
  effect: ReactiveEffect,
  scope: EffectScope | undefined = activeEffectScope
) {
  if (scope && scope.active) {
    scope.effects.push(effect)
  }
}

// effectScope用于多一个effect或者watch一起执行,在条件不允许的情况下
// 也能被正常的销毁

Track、Trigger


type KeyToDepMap = Map<any, Dep>
const targetMap = new WeakMap<any, KeyToDepMap>()

/*
 一个应用的依赖
 weakMap: {
   [target:一个对象] : Map: {
     [target.keys()]: Set: [effect]
     }
 }
*/

export function track(target: object, type: TrackOpTypes, key: unknown) {
  // 需要收集,并且,当前effect存在,存在副作用函数
  if (shouldTrack && activeEffect) {

    // 获取
    let depsMap = targetMap.get(target)
    if (!depsMap) {
      targetMap.set(target, (depsMap = new Map()))
    }
    let dep = depsMap.get(key)
    if (!dep) {
      depsMap.set(key, (dep = createDep()))
    }

    const eventInfo = __DEV__
      ? { effect: activeEffect, target, type, key }
      : undefined


    // dep -> set<Effect>
    trackEffects(dep, eventInfo)
  }
}

export function trackEffects(
  dep: Dep,
  debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
  let shouldTrack = false
  if (effectTrackDepth <= maxMarkerBits) {
    if (!newTracked(dep)) {
      dep.n |= trackOpBit // set newly tracked
      shouldTrack = !wasTracked(dep)
    }
  } else {
    // 如果依赖项中已经存在活跃的effect,跳过
    shouldTrack = !dep.has(activeEffect!)
  }

  if (shouldTrack) {
    // 把活跃的effect,添加到当前获取key的deps中

    dep.add(activeEffect!)
    // 双向绑定, 在stop时,可以直接从依赖中删除
    activeEffect!.deps.push(dep)

    if (__DEV__ && activeEffect!.onTrack) {
      activeEffect!.onTrack(
        Object.assign(
          {
            effect: activeEffect!
          },
          debuggerEventExtraInfo
        )
      )
    }


  }
}

export function trigger(
  target: object,
  type: TriggerOpTypes,
  key?: unknown,
  newValue?: unknown,
  oldValue?: unknown,
  oldTarget?: Map<unknown, unknown> | Set<unknown>
) {
  const depsMap = targetMap.get(target)
  if (!depsMap) {
    // 当前的keyMap没有可以通知的effect
    return
  }

  let deps: (Dep | undefined)[] = []

  if (type === TriggerOpTypes.CLEAR) {
   // 触发所有dep, set展开
    deps = [...depsMap.values()]
  } else if (key === 'length' && isArray(target)) {
    // 是数组的情况,就把dep:set 加入到deps中,用于触发
    depsMap.forEach((dep, key) => {
      if (key === 'length' || key >= (newValue as number)) {
        deps.push(dep)
      }
    })
  } else {

    if (key !== void 0) {
      deps.push(depsMap.get(key))
    }

    // 对于Map,set继续收集
    switch (type) {
      case TriggerOpTypes.ADD:
        if (!isArray(target)) {
          deps.push(depsMap.get(ITERATE_KEY))
          if (isMap(target)) {
            deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))
          }
        } else if (isIntegerKey(key)) {
          // new index added to array -> length changes
          deps.push(depsMap.get('length'))
        }
        break
      case TriggerOpTypes.DELETE:
        if (!isArray(target)) {
          deps.push(depsMap.get(ITERATE_KEY))
          if (isMap(target)) {
            deps.push(depsMap.get(MAP_KEY_ITERATE_KEY))
          }
        }
        break
      case TriggerOpTypes.SET:
        if (isMap(target)) {
          deps.push(depsMap.get(ITERATE_KEY))
        }
        break
    }
  }

  const eventInfo = __DEV__
    ? { target, type, key, newValue, oldValue, oldTarget }
    : undefined

  if (deps.length === 1) {
    // 只存在一个单独触发
    if (deps[0]) {
      if (__DEV__) {
        triggerEffects(deps[0], eventInfo)
      } else {
        triggerEffects(deps[0])
      }
    }
  } else {
    // 存在多个,分批处理
    const effects: ReactiveEffect[] = []
    for (const dep of deps) {
      if (dep) {
        effects.push(...dep)
      }
    }
    // 创建一个set,防止重复
    if (__DEV__) {
      triggerEffects(createDep(effects), eventInfo)
    } else {
      triggerEffects(createDep(effects))
    }
  }
}

export function triggerEffects(
  dep: Dep | ReactiveEffect[],
  debuggerEventExtraInfo?: DebuggerEventExtraInfo
) {
  // spread into array for stabilization
  for (const effect of isArray(dep) ? dep : [...dep]) {
    if (effect !== activeEffect || effect.allowRecurse) {

      if (__DEV__ && effect.onTrigger) {
        effect.onTrigger(extend({ effect }, debuggerEventExtraInfo))
      }
      // computed存在scheduler
      if (effect.scheduler) {
        effect.scheduler()
      } else {
        // 如果更新过程中存在副作用,继续使用effect收集
        effect.run()
      }

    }
  }
}

总体的一个流程,还是沿用vue2的响应式原理,获取时收集依赖,设置时触发更新,之前的watcher也可以被effect代替

比如实现一个简易的依赖收集系统



let activeEffect = null;

function effect(fn) {
  let run = () => fn();
  activeEffect = run;
  run();
  activeEffect = null;
}

let deps = new Set<Function>();

function track() {
  if (activeEffect != null) {
    deps.add(activeEffect);
  }
}

function trigger(newVal, oldValue) {
  deps.forEach(effect => effect(newVal, oldValue));
}

function ref(value) {

  const ans = {
    get value() {
      track();
      return value;
    },
    set value(newVal) {
      let oldValue = value;
      value = newVal;
      trigger(newVal, oldValue)
    }
  };
  return ans;
}