读这篇文章前,最好是先读vue数据绑定源码,由于本篇是接这章写的,放在一篇文章里,篇幅太大,我只好分红两章了。vue
Vue.prototype._init = function (options) { initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate') initInjections(vm) // resolve injections before data/props initState(vm) // 初始化数据的入口 initProvide(vm) // resolve provide after data/props callHook(vm, 'created') if (vm.$options.el) { vm.$mount(vm.$options.el) // 挂载组件 } } // mountComponent是在挂载组件时调用的方法 export function mountComponent (vm, el ,hydrating) { callHook(vm, 'beforeMount') let updateComponent = () => { vm._update(vm._render(), hydrating) } new Watcher(vm, updateComponent, noop, null, true /* isRenderWatcher */) if (vm.$vnode == null) { vm._isMounted = true callHook(vm, 'mounted') } return vm }
上一篇文章,咱们已经了解了Observer
、Dep
、Watcher
都是负责什么?如何互相协做?
接下来,咱们从数据的入口开始,了解vue是如何使用这几个类完成的数据驱动视图更新的?
初始化state,就是初始化这几个属性。node
先讲下什么是可观察者对象呢?
具有两个条件:
一、取值的时候,能把要取值的watcher
(观察者对象)加入它的dep
(依赖,也可叫观察者管理器)管理的subs
列表里(即观察者列表);
二、设置值的时候,有了变化,全部依赖于它的对象(即它的dep
里收集到的观察者watcher
)都获得通知。watcher
里面存储它都观察了谁(dep
),dep
里面存储了都谁观察了本身。segmentfault
循环每一个props
属性,对每一个属性调用defineReactive
,把每一个属性加上get
和set
装饰器,变为可观察者对象,若是属性值是对象也会递归转化。数组
observe
就是循环把data
中的全部项都转换成可观察者对象,若是子项是对象或数组就递归转化,确保data
里的每一项及其后代都转化成了可观察者对象
初始化数据时,无论data里的数据渲染用没用到,都会转成可观察者对象。
对于props
和data
,只有哪一个watcher
用到了去读取时,才会把该watcher
加到他的观察者列表中。ide
data
和props
里都调用了proxy
这个方法,他是作什么的呢?proxy(vm,’_data’,key)
proxy
就是把data
和props
下的属性都代理到了vm实例下,vm._data.a
等价于vm.a
原理就是Object.defineProperty
给vm
的key
属性设置get
和set
方法,当访问get
的时候,返回的是vm._data[key]
;当访问set
的时候,设置的是vm._data[key]
的值。oop
初始化计算属性,就是为每个计算属性定义一个Watcher
观察者对象。这个对象是lazy
的,不会当即就去执行计算(即get方法),等到用的时候才会去计算,这个时候就会去读取这个计算属性依赖的可观察属性的值来计算,读取的时候就会把这些依赖添加进这个计算watcher
里,同时这些依赖的订阅者列表也会加入这个计算watcher
。因此当依赖变化时,通知到他的全部订阅watcher
。计算watcher
接到依赖发生变化了,不会当即计算新值,而是标记dirty
为true
,读取这个计算属性的时候,发现dirty
为true
,就是说数据已经不是最新的了,须要从新计算,而后才去计算,不然直接取上一次计算的值value
。spa
若是某个data
经过计算属性间接的被用到了渲染里,那么这个data
也会被加入到渲染watcher
的依赖列表,它的订阅者列表也会保存渲染watcher
。
只有当模版里使用了该计算属性,这个计算属性依赖的可观察者才会被加入到渲染watcher
的依赖列表。若是模版里没有直接或间接用到可观察者对象属性,那么当你set
它的时候,也就不会触发更新操做。prototype
初始化watch
,就是为每一个watch
属性建立一个观察者对象,这个expOrFn
解析取值表达式去取值,而后就会调用相关data/prop
属性的get
方法,get
方法又会在他的观察者列表里加上该watcher
,一旦这些依赖属性值变化就会通知该watcher
执行update
方法。即会执行他的回调方法cb
,也就是watch
属性的handler
方法。代理
到这里,数据的初始化就完成了。code
这个方法是在,全部的数据初始化完成后,执行挂载组件时调用,建立一个渲染watcher
,每一个组件有且仅有一个渲染watcher
。updateComponent
是watcher
的getter
属性,建立后,当即调用get
方法,便是调用updateComponent
,也就是调用render
方法,render
里使用了的数据就会读取相关的data
的get
方法,就会把data
的依赖加进这个渲染watcher
的依赖列表里,data
的subs
也会加入渲染watcher
,如此,当设置data
时拦截的set
方法就会通知渲染watcher
调用update
方法。
我总结下:
一个数据变动后,通知他的Watcher去执行update。
不一样类型的Watcher职责不一样,vue里的Watcher能够分为3类:
渲染Watcher、计算Watcher、侦听器Watcher,注意这3中Watcher的getter属性分别是什么。