Vue源码分析(10)--实例分析computed和watch

前言

本文是vue2.x源码分析的第十篇,主要看computed和watch的处理过程!

实例代码




  
  Vue
  


  
{{messages}}

1 computed

关键断点
initState(vm);
if (opts.computed) { initComputed(vm, opts.computed); }
watchers[key] = new Watcher(vm, getter, noop,
computedWatcherOptions);//option中lazy:true导致watcher.get不执行,从而该watcher不收集dep,dep也不订阅该watcher
defineComputed(vm, key, userDef);
看下defineComputed

    function defineComputed (target, key, userDef) {
      if (typeof userDef === 'function') {
        sharedPropertyDefinition.get = createComputedGetter(key);
        sharedPropertyDefinition.set = noop;
      } else {
        sharedPropertyDefinition.get = userDef.get
          ? userDef.cache !== false
            ? createComputedGetter(key)
            : userDef.get
          : noop;
        sharedPropertyDefinition.set = userDef.set
          ? userDef.set
          : noop;
      }
      Object.defineProperty(target, key, sharedPropertyDefinition);
}

一句话总结computed原理:通过Object.defineProperty将计算属性的key(即messages)定义为vm的存取器属性,该key的get函数即是计算属性的value(即messages对应的函数),key的更新随着它所依赖的data中的某个属性一同更新

2 watch

关键断点
initState(vm);
if (opts.watch) { initWatch(vm, opts.watch); }
createWatcher(vm, key, handler);
vm.$watch(key, handler, options);
看下该函数:

    Vue.prototype.$watch = function (expOrFn,cb, options) {
        var vm = this;
        options = options || {};
        options.user = true;  //user watcher
        var watcher = new Watcher(vm, expOrFn, cb, options);
        if (options.immediate) {
          cb.call(vm, watcher.value);
        }
        return function unwatchFn () {
          watcher.teardown();
        }
    };
    var Watcher = function Watcher (vm,expOrFn,cb,options) {
      ...
      this.user=true;
      this.cb = cb;
      ...
      // parse expression for getter
      if (typeof expOrFn === 'function') { render watcher从这儿进
        this.getter = expOrFn;
      } else {
        this.getter = parsePath(expOrFn);  user watcher从这儿进
      }
      this.value = this.lazy
        ? undefined
        : this.get();
    };

接下来和render watcher一样执行get函数,然后message的dep订阅该user watcher,随后message的dep又订阅render watcher,也就是说message的dep.sub数组中有两个watcher,分别是user watcher和render watcher,页面初次渲染时user watcher不起什么作用,当message值改变导致页面更新时,先执行user watcher,这会执行该watcher.cb函数也即定义watch时的message的回调函数,从而实现了watch监控message变化的功能,然后执行render watcher实现页面更新。

你可能感兴趣的:(Vue源码分析(10)--实例分析computed和watch)