首先 要所有 option.data都会被proxy,
但 只有执行get的时候才会去收集依赖 ,
且一个组件只有一个watcher , 由于js是单线程,所以一个时刻只有一个watcher在执行
那么
- vue 是怎么收集依赖的呢
可以当页面执行 mountComponent的时候 ,触发Object.defineProperty的函数
const dep = new Dep()
一个option.data 选项会有一个dep 实例
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
addDep (dep: Dep) {
const id = dep.id
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}
addSub (sub: Watcher) {
this.subs.push(sub)
}
这里逻辑有一点绕 ,这里实际 是把watcher 收集到dep实例的subs 中, 用dep实例来管理watcher ,从而使 dep实例(观察目标)与 wacther(观察者)建立了联系,即与option.data选项建立了联系
由此可以预见的是如果是一个dep实例的subs 只有一个元素且 是同一个wacher
[Watcher]
0: Watcher
active: true
before: ƒ before()
cb: ƒ noop(a, b, c)
deep: false
depIds: Set(2) {15, 16}
deps: (2) [Dep, Dep]
dirty: false
expression: "function () {↵ debugger↵ vm._update(vm._render(), hydrating);↵ }"
getter: ƒ ()
id: 2
lazy: false
newDepIds: Set(0) {}
newDeps: []
sync: false
user: false
value: undefined
vm: VueComponent {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
[Watcher]
0: Watcher
active: true
before: ƒ before()
cb: ƒ noop(a, b, c)
deep: false
depIds: Set(2) {15, 16}
deps: (2) [Dep, Dep]
dirty: false
expression: "function () {↵ debugger↵ vm._update(vm._render(), hydrating);↵ }"
getter: ƒ ()
id: 2
lazy: false
newDepIds: Set(0) {}
newDeps: []
sync: false
user: false
value: undefined
vm: VueComponent {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
-
收集依赖收集 的是什么呢
由上可见 ,vue 把 watcher 当 依赖收集起来了 -
如果页面是由组件组合 起来的 ,那 收集的依赖又是怎样的呢
我的示例代码 是这样的:
<div id="app">
<hello-world></hello-world>
{{name}}
{{age}}
</div>
HelloWorldHelloWorldHelloWorld {{name}} {{age}}
```javascript 在这里插入代码片 ``` 输出的结果是: ```javascript Dep {id: 15, subs: Array(1)} [Watcher] 0: Watcher active: true before: ƒ before() cb: ƒ noop(a, b, c) deep: false depIds: Set(0) {} deps: [] dirty: false expression: "function () {↵ debugger↵ vm._update(vm._render(), hydrating);↵ }" getter: ƒ () id: 2 lazy: false newDepIds: Set(1) {15} newDeps: [Dep] sync: false user: false vm: VueComponent {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …} ```
HelloWorldHelloWorldHelloWorldHelloWorld
Dep {id: 16, subs: Array(1)}
[Watcher]0: Watcheractive: truebefore: ƒ before()cb: ƒ noop(a, b, c)deep: falsedepIds: Set(0) {}deps: []dirty: falseexpression: "function () {↵ debugger↵ vm._update(vm._render(), hydrating);↵ }"getter: ƒ ()id: 2lazy: falsenewDepIds: Set(2) {15, 16}newDeps: (2) [Dep, Dep]sync: falseuser: falsevm: VueComponent {_uid: 3, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}__proto__: Objectlength: 1__proto__: Array(0)
Dep {id: 20, subs: Array(1)}
[Watcher]
0: Watcher
active: true
before: ƒ before()
cb: ƒ noop(a, b, c)
deep: false
depIds: Set(0) {}
deps: []
dirty: false
expression: "function () {↵ debugger↵ vm._update(vm._render(), hydrating);↵ }"
getter: ƒ ()
id: 3
lazy: false
newDepIds: Set(1) {20}
newDeps: [Dep]
sync: false
user: false
vm: VueComponent {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
Dep {id: 21, subs: Array(1)}
[Watcher]
0: Watcher
active: true
before: ƒ before()
arguments: (...)
caller: (...)
length: 0
name: "before"
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: vue.runtime.esm.js?2b0e:4083
[[Scopes]]: Scopes[4]
cb: ƒ noop(a, b, c)
deep: false
depIds: Set(0) {}
deps: []
dirty: false
expression: "function () {↵ debugger↵ vm._update(vm._render(), hydrating);↵ }"
getter: ƒ ()
id: 3
lazy: false
newDepIds: Set(2) {20, 21}
newDeps: (2) [Dep, Dep]
sync: false
user: false
vm: VueComponent {_uid: 4, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
__proto__: Object
length: 1
__proto__: Array(0)
可以看出当前只有一个watcher(3或4)在执行 ,而且收集依赖的顺序是先父后子