美文网首页
vue源码分析(十四)核心函数之Watcher

vue源码分析(十四)核心函数之Watcher

作者: vue爱好者 | 来源:发表于2020-04-21 20:51 被阅读0次

    我们打开文件 src/core/observer/watcher.js
    由于文件代码量过多,我们一一来看,就不一次性帖出来了, Watcher类主要有如下方法:

    constructor 初始化构造函数
    get 计算getter
    addDep 添加依赖项
    cleanupDeps 清理依赖项
    update 依赖项更改时调用
    run 调用处理函数
    evaluate 重新计算值,这只适用于懒惰的观察者
    depend 调用Dep的depend函数
    teardown 从所有依赖项的订阅服务器列表中移除

    我们接下来看几个主要的,简单的我们就略过了:

    constructor

    constructor (
        vm: Component,
        expOrFn: string | Function,
        cb: Function,
        options?: ?Object,
        isRenderWatcher?: boolean
      ) {
        this.vm = vm
        if (isRenderWatcher) {
          vm._watcher = this
        }
        vm._watchers.push(this)
    
        // 省略部分代码...
    
       // 表达式是否是函数
        if (typeof expOrFn === 'function') {
          this.getter = expOrFn
        } else {
          this.getter = parsePath(expOrFn)
          if (!this.getter) {
            this.getter = noop
            process.env.NODE_ENV !== 'production' && warn(
              `Failed watching path: "${expOrFn}" ` +
              'Watcher only accepts simple dot-delimited paths. ' +
              'For full control, use a function instead.',
              vm
            )
          }
        }
        this.value = this.lazy
          ? undefined
          : this.get()
      }
    

    可以看到有对 expOrFn 参数进行类型判断,因为他可能有两种类型 expOrFn: string | Function 字符串和函数。
    接下来如果 this.lazy为真就给value赋值为 'undefined',否则就调用get函数进行处理。

    get

     /**
       * Evaluate the getter, and re-collect dependencies.
       */
      get () {
        //入栈操作
        pushTarget(this)
        let value
        const vm = this.vm
        try {
         // 调用 'constructor '处理好的getter函数
          value = this.getter.call(vm, vm)
        } catch (e) {
          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
          // 如果'deep'为真,就对value进行一个深度监听。
          if (this.deep) {
            traverse(value)
          }
          //出栈操作
          popTarget()
         // 清理依赖项
          this.cleanupDeps()
        }
        return value
      }
    
    

    可以看到首先进行了一个 入栈操作pushTarget(this),然后调用 constructor 里面处理好的 getter 函数,完成之后判断 deep 是否 为真,就对value进行一个深度监听。紧接着就是出栈操作。
    最后 调用 this.cleanupDeps() 清理依赖项 。

    update

    /**
       * Subscriber interface.
       * Will be called when a dependency changes.
       */
      update () {
        /* istanbul ignore else */
        if (this.lazy) {
          this.dirty = true
        } else if (this.sync) {
          this.run()
        } else {
          queueWatcher(this)
        }
      }
    

    1、如果 lazy 属性为真就把 dirty 标识为真。
    2、如果 sync 属性为真,就调用run方法。
    3、否则就调用 queueWatcher 函数,把this推入到列队里面。

    run

    /**
       * Scheduler job interface.
       * Will be called by the scheduler.
       */
      run () {
        if (this.active) {
          const value = this.get()
          if (
            value !== this.value ||
            // Deep watchers and watchers on Object/Arrays should fire even
            // when the value is the same, because the value may
            // have mutated.
            isObject(value) ||
            this.deep
          ) {
            // set new value
            const oldValue = this.value
            this.value = value
            if (this.user) {
              try {
                this.cb.call(this.vm, value, oldValue)
              } catch (e) {
                handleError(e, this.vm, `callback for watcher "${this.expression}"`)
              }
            } else {
              this.cb.call(this.vm, value, oldValue)
            }
          }
        }
      }
    

    首先判断 active 是否为真,默认就是 true,如果是false的话,那就是移除了监听器,或者组件被移除了(调用了destroy生命周期)。

    (active=false代表已被销毁),调用unwatcher和触发destroy都会销毁active

    紧接着调用了get方法,获取最新的value值,然后判断最新的值是否和旧值相等,或者最新的值是object对象,或者存在deep选项。
    最后调用 cb函数(一般是用户自定义hanle方法,或者vue自带的一个空函数) 处理。

    相关文章

      网友评论

          本文标题:vue源码分析(十四)核心函数之Watcher

          本文链接:https://www.haomeiwen.com/subject/ckadyhtx.html