vue源码阅读之Watcher类

vue源码阅读之Watcher类_第1张图片

我们上次分析vue源码讲的是收集依赖,数据变化之后我们把依赖收集到dep类中,通过这个管理器进行管理。

里面有一个subs数组,用来存放依赖,并且定义了几个实例方法用来依赖进行添加,删除,通过操作。

比如addSub,removeSub,depend、notify等方法。

依赖到底是谁

我们dep是用来管理依赖的,那么要添加的依赖到底是谁?

其实这个依赖就是我们常说的watcher的类,也就是说谁用了数据,谁就是那个依赖。

谁用到了数据,我们就为谁创建一个Watcher实例。在之后数据变化的时候,我们不去直接通知依赖更新,而是通知依赖对应的Watch实例,由Watcher实例去通知真正的视图。

export default class Watcher implements DepTarget {
}

这个就是Watcher类,实现了DepTarget。
而DepTarget这个接口在dep类里面实现的。

export interface DepTarget extends DebuggerOptions {
  id: number
  addDep(dep: Dep): void
  update(): void
}

Wathcer构造函数

下面是Watcher构造函数的源码。

constructor(
    vm: Component | null,
    expOrFn: string | (() => any),
    cb: Function,
    options?: WatcherOptions | null,
    isRenderWatcher?: boolean
  ) {
    // 初始化代码
    // 此处省略部分代码...
    this.value = this.lazy ? undefined : this.get()
  }

这个就是在创建Watcher实例的时候初始执行的部分。在创建Watcher实例的时候会自动把自己添加到这个数据的依赖管理器中。

在最后一行有个this.value,执行了this.get();

这个get函数源码如下

 get() {
    pushTarget(this)
    let value
    const vm = this.vm
    try {
      value = this.getter.call(vm, vm)
    } catch (e: any) {
      if (this.user) {
        handleError(e, vm, `getter for watcher "${this.expression}"`)
      } else {
        throw e
      }
    } finally {
      // "touch" every property so they are all tracked as
      // dependencies for deep watching
      if (this.deep) {
        traverse(value)
      }
      popTarget()
      this.cleanupDeps()
    }
    return value
  }

这里get函数第一步就是把这个watcher实例给了Dep.target。

然后在通过this.getter.call(vm, vm)获取一下被依赖的数据,这里的getter就是
vue源码阅读之Watcher类_第2张图片
更新组件重新传染函数updateComponent。

当数据发生变化的时候,会触发set函数,set函数接着会触发dep.nofity函数。然后执行Watcher类中的update()方法,调用数据变化的更新回调函数,从而更新视图。

你可能感兴趣的:(vue.js,前端,javascript)