关于vue.js:Vue源码中对Watcher执行的分析

8次阅读

共计 1619 个字符,预计需要花费 5 分钟才能阅读完成。

触发更新时 watcher 的执行

  • watcher 分为三种,Computed Watcher,用户 Watcher 侦听器,渲染 Watcher
  • 前两种 initState 时初始化
  • 渲染 watcher 在 core/instance/lifecycle.js 中 mountComponent,后执行
  • 当调用 dep.notify 时,会对 watcher 排序,而后顺次更新 watcher.update
  • 对于不同类型 watcher,update 解决形式不同
  • 渲染 watcher 会判断 以后组件 watcher 是否放入队列中,未放入 则找到地位插入到队列中
  • 调用 flushSchedulerQueue 办法

    • 先更新父组件后更新子组件(父组件先创立)
    • 用户 watchers 在渲染 watcher 之前运行,(用户或计算属性在 initState 中创立,在 mountComponent 之前)
    • 如果一个组件在父组件执行期间被销毁,则跳过以后组件
    • 遍历队列中的 watcher,调用 watcher.run()
    • run 办法内 调用 get 办法,get 办法调用 了 this.getter.call(vm, vm)
    • this.getter 就是 updateComponent 办法
  • 更新完结后重置状态
  • 调用 activated,updated 两个钩子

    notify () {
    
    // copy
    const subs = this.subs.slice()
    
    if (process.env.NODE_ENV !== 'production' && !config.async) {
    
      // 按 watcher 的创立程序排序
      subs.sort((a, b) => a.id - b.id)
    }
    
    // 调用 watcher 的 更新
    for (let i = 0, l = subs.length; i < l; i++) {subs[i].update()}
    }
    update () {
    // 三种 watcher update 渲染 watcher 走 else
    
    if (this.lazy) {this.dirty = true} else if (this.sync) {this.run()
    } else {queueWatcher(this)
    }
    }
    export function queueWatcher (watcher: Watcher) {
    const id = watcher.id
    
    // has 是个对象,避免 watcher 被反复解决
    if (has[id] == null) {has[id] = true
    
      // flushing = true 示意 watcher 对象正在被解决
      // 把 watcher 放入队列中
      if (!flushing) {queue.push(watcher)
      } else {
    
        let i = queue.length - 1
    
        // 队列未解决完,从后向前取 watcher 和以后组件 watcher 比拟,确定 i
        while (i > index && queue[i].id > watcher.id) {i--}
        
        // 把组件 watcher 插入对应地位
        queue.splice(i + 1, 0, watcher)
      }
      
      // waiting = true 示意 以后队列正在执行
      if (!waiting) {
        waiting = true
    
        if (process.env.NODE_ENV !== 'production' && !config.async) {// 遍历所有 watcher, 调用 watcher.run()
          flushSchedulerQueue()
    
          return
        }
    
        // 生产环境会传入 nextTick,nextTick(flushSchedulerQueue)
      }
    }
    }
    function flushSchedulerQueue () {
    ... // 把 watcher 插入队列
    
    // 遍历队列内的 watcher 执行 run
    watcher.run()
    ...
    }
    run () {
    ...
    this.get() // this 指 watcher
    ...
    }
    get () {pushTarget(this)
    ...
    // this.getter 为 updateComponent
    value = this.getter.call(vm,vm)
    }
正文完
 0