Vue3----reactive原理解析

100 阅读3分钟

步骤一:

reactive 函数在 packages/reactivity/src/reactive.ts 文件下:

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
  )
}

reactive 函数实际执行的是 createReactiveObject 方法,而 target 参数就是我们传进来的对象。

步骤二:

createReactiveObject 函数,该函数在 packages/reactivity/src/reactive.ts 文件下:

function createReactiveObject(
  target: Target,
  isReadonly: boolean,
  baseHandlers: ProxyHandler<any>,
  collectionHandlers: ProxyHandler<any>,
  proxyMap: WeakMap<Target, any>
) {
  // 省略
  // target already has corresponding Proxy
  // 缓存中读取 存在则直接返回
  const existingProxy = proxyMap.get(target)
  if (existingProxy) {
    return existingProxy
  }
  // 省略
  // 这里的 baseHandlers 参数 就是传进来的 mutableHandlers
  const proxy = new Proxy(
    target,
    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers
  )
  // 设置缓存
  proxyMap.set(target, proxy)
  // 返回 proxy 实例对象
  return proxy
}

createReactiveObject 函数做了 proxyMap 缓存处理,最终返回一个 proxy 实例对象。new Proxy 这段代码,第一个参数 target 为传进来的对象,即 { name: 'x x x', age: 18 },第二个 baseHandlers 参数即传入的 mutableHandlers 对象,

步骤三:

mutableHandlers对象定义在packages/reactivity/src/baseHandlers.ts

export const mutableHandlers: ProxyHandler<object> = {
  get,
  set,
  deleteProperty,
  has,
  ownKeys
}

该对象定义了getset方法,对传入的数据进行依赖收集和依赖触发。

总结:ractive函数执行完毕,obj得到一个proxy的实例对象。接着又执行effect方法。

步骤四:

effect方法定义在packages/reactivity/src/effect.ts文件:

export function effect<T = any>(
  fn: () => T,
  options?: ReactiveEffectOptions
): ReactiveEffectRunner {
  if ((fn as ReactiveEffectRunner).effect) {
    fn = (fn as ReactiveEffectRunner).effect.fn
  }
  // 创建 ReactiveEffect 实例
  const _effect = new ReactiveEffect(fn)
  // 省略
  if (!options || !options.lazy) {
   // 执行 ReactiveEffect 中的 run 方法
    _effect.run()
  }
  // 省略
}

effect函数先声明一个构造函数ReactiveEffect的实例对象_effect,然后执行构造函数中的run 方法

总结:

第一部分:

  • reactive 函数实际执行了 createReactiveObject 方法。

  • createReactiveObject 函数做了proxyMap缓存处理,返回一个 proxy 实例对象。

  • new proxy传两个参数,第一个是target,即为传进来的对象,第二个是baseHandlers参数,即传入的mutableHandlers对象。

  • mutableHandlers对象定义了getsethas等方法,对传入的数据进行依赖收集和依赖触发。

    • get 方法实际执行了 createGetter 方法,该方法中 track 函数来进行依赖收集,
    • set 方法实际执行了 createSetter 方法,该方法中 trigger 进行依赖触发。

第二部分:reactive 函数执行完毕,obj 得到了一个 proxy 的实例对象。接着又执行 effect 方法

  • effect 函数声明一个构造函数 ReactiveEffect 的实例对象_effect,执行构造函数中的run 方法

  • ReactiveEffect做了两件事,第一是在 run 函数中给 avtiveEffect 赋值,第二是执行 fn 函数。

  • 执行fn函数,就会触发obj的get方法,就会激活 track 方法,构建 WeakMaptargetMap 对象,从而完成指定对象指定属性到 effect 的依赖收集的工作。

  • 此时已经完成了一个依赖收集,之后进行依赖触发 setter

  • set 方法实际执行了 createSetter 方法,然后触发 trigger 函数进行依赖触发。

  • trigger 函数中首先或从之前 targetMap 依赖收集的对象中获取,根据 key 获取到 effect,然后执行 fn 函数,从而完成一个依赖触发的过程。

reactive 缺陷:

  • 一是解构后不支持响应性

  • 二是不支持基本类型,只能是对象