vue观察者原理一分钟速览

数据驱动视图:

  1. 理解watcher、dep、observer这三个对象之间的关系
  2. 这和VUE对象又有什么关系?
  3. 这和视图又有什么关系?

翻看了文档。找到了一段清晰的代码,

var vm = new Vue({
	  data: { a: 1 },
	  computed: {
	    // 仅读取
	    aDouble: function () {
	      return this.a * 2
	    },
	    // 读取和设置
	    aPlus: {
	      get: function () {
	        return this.a + 1
	      },
	      set: function (v) {
	        this.a = v - 1
	      }
	    }
	  }
	})

然后带着上面的问题,去阅读了vue的构造过程,在initState中发现了computed的构造,其中有一个关键的用法:

function initComputed (vm: Component) {
	const computed = vm.$options.computed
	...
	const userDef = computed[key]
	makeComputedGetter(userDef, vm)
	...
}

	function makeComputedGetter (getter: Function
	, owner: Component): Function {
  		const watcher = new Watcher(owner, getter, noop, {
    		lazy: true
  		})
  	...
  	}

对于观察者来说用户定义的函数是getter

也就是对于框架底层来说,程序员写的computed函数,对组件来说是getter。computed实际上是用包装了一下用户定义的函数。

可以把他理解成一种特殊的watcher,根据官方的文档,提到了computed有缓存功能,不会更新相同的结果。简单起见我们就把computed当作watcher理解。

然后开始关注这个函数内部发生了什么:

...
computed: {
	    // 仅读取
	    aDouble: function () {
	      return this.a * 2
	    },
...

这里读取了this.a。

想起来vue内部的变量都是处理过的。

用了observe这个工厂方法加工过,setget都和watcherdeb耦合。

执行aDouble这个函数,computed就作为一个watcherDep.target记住了,而a就是一个obsserver,调用了get就会将watcher保存在deps数组中,就好像a调用get就被aDouble盯上(watch)了,下次a变化(调用a.set)就重新执行一遍aDouble

这个时候我们再回去看wacher对象,发现这个对象有一个cb存放回调函数,而且代码中还出来了属于VNode模块的**patch**。

cb应该是负责重新渲染视图。

所以这就可以解释VUE是如何驱动视图改变的,源自于一种自动更新的一对多机制。这可以解决父子组件的通信问题,父子组件状态同步可以通过向子组件注入父组件的数据引用,可以实现单向数据流。

查看了官方文档:

每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据属性记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

证实了掘金那个作者说的没错,每一个vue的确有一个watcher

查看watcher.get的call stack:

get (vue.js:647)
Watcher (vue.js:638)
Vue.$watch (vue.js:1254)
createWatcher (vue.js:1232)
initWatch (vue.js:1217)
initState (vue.js:1105)
Vue._init (vue.js:2110)
Vue (vue.js:2150)
(anonymous) (app.js:7)

我们看到Vue.$watch说明vue下确实有一个watcher

这个watcher目的是什么呢?我们回去看了一下watch的构造函数

constructor (
    vm: Component,
    expOrFn: string | Function,
    cb: Function,
    options?: Object = {}
  ) {
	 ... 
	 this.getter = parsePath(expOrFn)
	 this.value = this.lazy
	       ? undefined
	       : this.get()
	 ...
  }

在parsePath之中会触发所有vue的内部对象的get的函数句柄,然后被执行,所有的内部数据改动都会导致wacher重新渲染数据

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值