We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
本文是针对[email protected]进行分析
[email protected]
observer是Vue核心中最重要的一个模块(个人认为),能够实现视图与数据的响应式更新,底层全凭observer的支持。
observer
observer模块在Vue项目中的代码位置是src/core/observer,模块共分为这几个部分:
src/core/observer
Observer
Watcher
Dep
示意图如下:
Observer类定义在src/core/observer/index.js中,先来看一下Observer的构造函数
src/core/observer/index.js
constructor (value: any) { this.value = value this.dep = new Dep() this.vmCount = 0 def(value, '__ob__', this) if (Array.isArray(value)) { const augment = hasProto ? protoAugment : copyAugment augment(value, arrayMethods, arrayKeys) this.observeArray(value) } else { this.walk(value) } }
value是需要被观察的数据对象,在构造函数中,会给value增加__ob__属性,作为数据已经被Observer观察的标志。如果value是数组,就使用observeArray遍历value,对value中每一个元素调用observe分别进行观察。如果value是对象,则使用walk遍历value上每个key,对每个key调用defineReactive来获得该key的set/get控制权。
value
__ob__
observeArray
observe
walk
defineReactive
set/get
解释下上面用到的几个函数的功能:
new Observer
Object.defineProperty
get
set
notify
watcher
如果不太理解上面的文字描述可以看一下图:
Dep是Observer与Watcher之间的纽带,也可以认为Dep是服务于Observer的订阅系统。Watcher订阅某个Observer的Dep,当Observer观察的数据发生变化时,通过Dep通知各个已经订阅的Watcher。
Dep提供了几个接口:
addSub
removeSub
depend
Dep.target
addDep
Watcher是用来订阅数据的变化的并执行相应操作(例如更新视图)的。Watcher的构造器函数定义如下:
constructor (vm, expOrFn, cb, options) { this.vm = vm vm._watchers.push(this) // options if (options) { this.deep = !!options.deep this.user = !!options.user this.lazy = !!options.lazy this.sync = !!options.sync } else { this.deep = this.user = this.lazy = this.sync = false } this.cb = cb this.id = ++uid // uid for batching this.active = true this.dirty = this.lazy // for lazy watchers this.deps = [] this.newDeps = [] this.depIds = new Set() this.newDepIds = new Set() this.expression = process.env.NODE_ENV !== 'production' ? expOrFn.toString() : '' if (typeof expOrFn === 'function') { this.getter = expOrFn } else { this.getter = parsePath(expOrFn) if (!this.getter) { this.getter = function () {} process.env.NODE_ENV !== 'production' && warn( `Failed watching path: "${expOrFn}" ` + 'Watcher only accepts simple dot-delimited paths. ' + 'For full control, use a function instead.', vm ) } } this.value = this.lazy ? undefined : this.get() }
参数中,vm表示组件实例,expOrFn表示要订阅的数据字段(字符串表示,例如a.b.c)或是一个要执行的函数,cb表示watcher运行后的回调函数,options是选项对象,包含deep、user、lazy等配置。
vm
expOrFn
a.b.c
cb
options
deep
user
lazy
watcher实例上有这些方法:
this.getter
dep
cleanupDeps
newDepIds
newDep
update
run
this.get()
evaluate
this.deps
teardown
在src/core/observer/array.js中,Vue框架对数组的push、pop、shift、unshift、sort、splice、reverse方法进行了改造,在调用数组的这些方法时,自动触发dep.notify(),解决了调用这些函数改变数组后无法触发更新的问题。在Vue的官方文档中对这个也有说明:http://cn.vuejs.org/v2/guide/list.html#变异方法
src/core/observer/array.js
push
pop
shift
unshift
sort
splice
reverse
dep.notify()
The text was updated successfully, but these errors were encountered:
No branches or pull requests
observer
是Vue核心中最重要的一个模块(个人认为),能够实现视图与数据的响应式更新,底层全凭observer
的支持。observer
模块在Vue项目中的代码位置是src/core/observer
,模块共分为这几个部分:Observer
: 数据的观察者,让数据对象的读写操作都处于自己的监管之下Watcher
: 数据的订阅者,数据的变化会通知到Watcher
,然后由Watcher
进行相应的操作,例如更新视图Dep
:Observer
与Watcher
的纽带,当数据变化时,会被Observer
观察到,然后由Dep
通知到Watcher
示意图如下:
Observer
Observer
类定义在src/core/observer/index.js
中,先来看一下Observer
的构造函数value
是需要被观察的数据对象,在构造函数中,会给value
增加__ob__
属性,作为数据已经被Observer
观察的标志。如果value
是数组,就使用observeArray
遍历value
,对value
中每一个元素调用observe
分别进行观察。如果value
是对象,则使用walk
遍历value
上每个key,对每个key调用defineReactive
来获得该key的set/get
控制权。解释下上面用到的几个函数的功能:
observeArray
: 遍历数组,对数组的每个元素调用observe
observe
: 检查对象上是否有__ob__
属性,如果存在,则表明该对象已经处于Observer
的观察中,如果不存在,则new Observer
来观察对象(其实还有一些判断逻辑,为了便于理解就不赘述了)walk
: 遍历对象的每个key,对对象上每个key的数据调用defineReactive
defineReactive
: 通过Object.defineProperty
设置对象的key属性,使得能够捕获到该属性值的set/get
动作。一般是由Watcher
的实例对象进行get
操作,此时Watcher
的实例对象将被自动添加到Dep
实例的依赖数组中,在外部操作触发了set
时,将通过Dep
实例的notify
来通知所有依赖的watcher
进行更新。如果不太理解上面的文字描述可以看一下图:
Dep
Dep
是Observer
与Watcher
之间的纽带,也可以认为Dep
是服务于Observer
的订阅系统。Watcher
订阅某个Observer
的Dep
,当Observer
观察的数据发生变化时,通过Dep
通知各个已经订阅的Watcher
。Dep
提供了几个接口:addSub
: 接收的参数为Watcher
实例,并把Watcher
实例存入记录依赖的数组中removeSub
: 与addSub
对应,作用是将Watcher
实例从记录依赖的数组中移除depend
:Dep.target
上存放这当前需要操作的Watcher
实例,调用depend
会调用该Watcher
实例的addDep
方法,addDep
的功能可以看下面对Watcher
的介绍notify
: 通知依赖数组中所有的watcher
进行更新操作Watcher
Watcher
是用来订阅数据的变化的并执行相应操作(例如更新视图)的。Watcher
的构造器函数定义如下:参数中,
vm
表示组件实例,expOrFn
表示要订阅的数据字段(字符串表示,例如a.b.c
)或是一个要执行的函数,cb
表示watcher运行后的回调函数,options
是选项对象,包含deep
、user
、lazy
等配置。watcher
实例上有这些方法:get
: 将Dep.target
设置为当前watcher
实例,在内部调用this.getter
,如果此时某个被Observer
观察的数据对象被取值了,那么当前watcher
实例将会自动订阅数据对象的Dep
实例addDep
: 接收参数dep
(Dep实例),让当前watcher
订阅dep
cleanupDeps
: 清除newDepIds
和newDep
上记录的对dep的订阅信息update
: 立刻运行watcher
或者将watcher
加入队列中等待统一flushrun
: 运行watcher
,调用this.get()
求值,然后触发回调evaluate
: 调用this.get()
求值depend
: 遍历this.deps
,让当前watcher
实例订阅所有dep
teardown
: 去除当前watcher
实例所有的订阅Array methods
在
src/core/observer/array.js
中,Vue框架对数组的push
、pop
、shift
、unshift
、sort
、splice
、reverse
方法进行了改造,在调用数组的这些方法时,自动触发dep.notify()
,解决了调用这些函数改变数组后无法触发更新的问题。在Vue的官方文档中对这个也有说明:http://cn.vuejs.org/v2/guide/list.html#变异方法The text was updated successfully, but these errors were encountered: