美文网首页
vue cumputed原理

vue cumputed原理

作者: 安石0 | 来源:发表于2019-08-23 09:39 被阅读0次

new Vue的时候:执行 initComputed (vm, computed)

function initComputed (vm, computed) {
...
for (var key in computed) {
    var userDef = computed[key];
    var getter = typeof userDef === 'function' ? userDef : userDef.get;
    if (!isSSR) {
      // create internal watcher for the computed property.
      watchers[key] = new Watcher(
        vm,
        getter || noop, // 这个值就是用户定义的computed: {key: val} 的val
        noop,
        computedWatcherOptions
      );
}
...
}

所以本质上computed是一个watcher

 constructor (
    vm: Component,
    expOrFn: string | Function,
    cb: Function,
    options?: ?Object,
    isRenderWatcher?: boolean
  ) {
...
 if (typeof expOrFn === 'function') {
// 这里的expOrFn就是用户定义的computed{key: val}中的val
      this.getter = expOrFn
    } 
...

}

假设用户computed中定义为

用户的computed中: {
    fullName () {
     // 'aa' + 'bb'
     return this.firstName + this.lastName
  }
}

假设这个时候firstName变成了'a' , lastName变成了'abb'
这两个值的变化都会触发派发更新
会触发watcher.update,当前的watcher为computed

 update () {
    /* istanbul ignore else */
    if (this.computed) {
      // A computed property watcher has two modes: lazy and activated.
      // It initializes as lazy by default, and only becomes activated when
      // it is depended on by at least one subscriber, which is typically
      // another computed property or a component's render function.
      if (this.dep.subs.length === 0) {
        // 当你并没有使用过这个computed的时候,其实就可以啥都不做
        // In lazy mode, we don't want to perform computations until necessary,
        // so we simply mark the watcher as dirty. The actual computation is
        // performed just-in-time in this.evaluate() when the computed property
        // is accessed.
        this.dirty = true
      } else {
        // In activated mode, we want to proactively perform the computation
        // but only notify our subscribers when the value has indeed changed.
       // 有使用的case
        this.getAndInvoke(() => {
          this.dep.notify()
        })
      }
    } else if (this.sync) {
      this.run()
    } else {
      queueWatcher(this)
    }
  }

上一步分析到:会执行

this.getAndInvoke(() => {
  this.dep.notify()  // this为当前的wacther
})

getAndInvoke

getAndInvoke (cb: Function) {
    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
      this.dirty = false
      if (this.user) {  
      // 我们在new Vue({watch: {}})写的watch
        try {
          cb.call(this.vm, value, oldValue)
        } catch (e) {
          handleError(e, this.vm, `callback for watcher "${this.expression}"`)
        }
      } else {
         // 这里执行上一步的 () => {this.dep.notify()}
        cb.call(this.vm, value, oldValue)
        // 这里会派发更新,像普通的data.fullName值一样,会重新渲染vue
      }
    }
  }

wacther.get

get () {
    pushTarget(this)
    let value
    const vm = this.vm
    try {
      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
      if (this.deep) {
        traverse(value)
      }
      popTarget()
      this.cleanupDeps()
    }
    return value
  }

结论:

computed初始化的时候做了一个get求值,执行了一次用户定义的表达式,这个computed watcher会订阅firstName和lastName的(执行过程中有其他的响应式数据也会订阅),firtName或者lastName变化会触发computed表达式执行,但是当新值和旧值相等时,不会触订阅了fullName的watcher更新。所以会有缓存一说。

附录1:响应式梳理

响应式梳理

相关文章

  • vue cumputed原理

    new Vue的时候:执行 initComputed (vm, computed) 所以本质上computed是一...

  • vue总结

    vue路由守卫 vue实现双向绑定原理 Vue生命周期: vue跨域方式 vue-router实现原理 vue-r...

  • 面试总结之基础(2)

    Vue2响应式原理 Vue3响应式原理

  • vue原理面试题资源整理

    vuex面试题 Vue生命周期 周期2 Vue通信 父子 兄弟 Vue响应式原理 MVVM Vue axios原理...

  • VUE(面试题)

    1、vue双向绑定原理vue2.x:vue双向绑定的原理是利用了Object.defineProperty()这个...

  • Vue面试题集锦

    VUE的双向绑定原理 原理:在创建Vue实例时,Vue会遍历data选项的属性,利用Object.definePr...

  • Vue响应式原理

    Vue2.x 核心响应式原理 Vue3.0 核心响应式原理 Vue 自定义事件 Vue 发布订阅模式 发布/订阅模...

  • Vue 父组件 传值 子组件 不生效

    原理 父组件.Vue 子组件.Vue 拓展

  • 前端TODO

    Vue.js 等框架原理了解 webpack 原理了解 browserify 插件开发 Vue.js 等框架原理学习

  • vue系列--- vue响应式原理

    vue响应式原理 要说vue响应式原理首先要说的是Object.defindProperty(),这个是响应式原理...

网友评论

      本文标题:vue cumputed原理

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