核心部件
Observer-观察者
作用: 将一个普通对象转换为一个响应式对象
响应式对象:简单来说就是每个属性都具有getter与setter方法的对象
实现原理: 遍历普通对象,通过Object.defineProperty方法重新定义普通对象中的每个属性,将其转化为响应式对象.数组对象,嵌套对象使用递归实现深层次遍历
该事件发生在beforeCreate与created之间
由于遍历时仅能遍历到对象的当前属性,因此无法检测到将来动态增加或者删除的属性,因此vue提供$set 和$delete 两个实例方法对已有的响应式对象进行添加或删除属性,但是这两个方法很有可能会引发没有必要的重新渲染,所以vue并不怎么推荐使用,而是期望我们在定义对象时給属性一个默认值null或者别的值
对于数组: vue会更改其隐式原型__proto__,增加vue自己写的pop,push,shift,unshift,sort,reverse,splice方法,之所以这样做是因为vue需要监听那些可能改变数组内容的方法
数组原型链: 数组 — vue自定义对象 — Array.prototype
Observer终极目标: 让对象的任何操作都能受到Vue监控
如上Observer解决了属性变化会通知vue,让Vue做操作的问题 但是 vue用通知谁去做呢?又要去做什么呢?
Dep – Dependency – 依赖
作用: 解决两个问题 1 读取属性时去做什么 2 属性改变时去做什么
vue会为响应式对象中的每个属性,对象本身,数组本身创建一个Dep实例,每个实例都有能力做到两件事
- 记录依赖: 当响应式对象的属性被读取时,它会进行依赖收集,既是谁用到了我
- 派发更新: 当改变某个属性时,它会通知那些用到我的人,我改变了
上述两点中的我指的是该属性,对象,或数组
Dep解决了Observer未能解决的做什么的问题,现在vue具有了能动态做事的能力,但是现阶段Dep实例只是知道去做事,还是不知道要谁去做事.
Watcher
作用: 完成闭环,解决是谁去做事的问题
拿render函数举例 ps: 不知道render函数的话去补补吧 render函数不会直接执行,而是交给Watcher去执行,在watcher要执行render之前,watcher将会在全局设置一个变量,并使其等于render,例如window.currentHandler = watcher.render(只是瞎举例),然后去执行函数render,当render执行过程中用到响应式数据,则会触发Dep实例的记录依赖功能,在这时,Dep会记录当前全局变量windowcurrentHandler的值,当Dep触发派发功能时,通知之前记录的watcher,响应式原理完成闭环 但是此时产生一个效率问题
foo() {
this.a = 1;
this.b = 2;
this.c = 3;
this.d = 4;
}
Scheduler–调度器
作用: 解决效率问题 其实Watcher在收到派发通知的时候并不会立即去执行对应的函数,而是把自己交给调度器Scheduler
Scheduler维护一个执行队列,该队列同一个Watcher仅会存在一次该队列的Watcher不会立即执行,他会通过一个nextTick的工具方法,把需要执行的watcher放入到事件循环的微队列中,nextTick的具体做法师通过Promise完成的
nextTick工具会通过$nextTick 暴露給开发者
也就是说,当响应式数据变化时,render函数的执行时异步的,并且在微队列中
不算太好理解,来搞个事情
<div id="app">
<h1 id="test">{{ a }}, {{ b }}</h1>
<button @click="changeSomething">改变</button>
</div>
<script>
const vm = new Vue({
el: "#app",
data() {
return {
a: 1,
b: 2
}
},
methods: {
changeSomething() {
this.$nextTick(()=> {
let h1 = document.getElementById("test");
console.log(h1.innerText);
});
this.a = 99;
this.b = 100;
}
},
})
</script>
|