Vue響應(yīng)式原理Observer梳杏、Dep掰读、Watcher理解
- Observer
- Observer是用來給數(shù)據(jù)添加Dep依賴蹈集。
class Observer {
constructor() {
// 響應(yīng)式綁定數(shù)據(jù)通過方法
observe(this.data);
}
}
export function observe (data) {
const keys = Object.keys(data);
for (let i = 0; i < keys.length; i++) {
// 將data中我們定義的每個屬性進(jìn)行響應(yīng)式綁定
defineReactive(obj, keys[i]);
}
}
- Dep 管理依賴
Dep是data每個對象包括子對象都擁有一個該對象, 當(dāng)所綁定的數(shù)據(jù)有變更時, 通過dep.notify()通知Watcher拢肆。
-
Dep就是幫我們收集【究竟要通知到哪里的】靖诗。
<div> <p>{{message}}</p> </div>
data: { text: 'hello world', message: 'hello vue', }
- 雖然data中有text和message屬性刊橘,但是只有message被渲染到頁面上,至于text無論怎么變化都影響不到視圖的展示攒庵,因此我們僅僅對message進(jìn)行收集即可败晴,可以避免一些無用的工作。
- 當(dāng)使用watch屬性時稳懒,也就是開發(fā)者自定義的監(jiān)聽某個data中屬性的變化慢味。比如監(jiān)聽message的變化纯路,message變化時我們就要通知到watch這個鉤子,讓它去執(zhí)行回調(diào)函數(shù)装哆。定嗓,第二個依賴就是用來管理watch中message變化的。
- 這個時候message的Dep就收集到了兩個依賴
- 依賴1: data中message的變化
- 依賴2: watch監(jiān)聽message的變化
watch: { message: function (val, oldVal) { console.log('new: %s, old: %s', val, oldVal) }, }
-
開發(fā)者自定義computed計(jì)算屬性時凌简,如下 messageTransfer 屬性雏搂,是依賴message的變化的。因此message變化時我們也要通知到computed凸郑,讓它去執(zhí)行回調(diào)函數(shù)。 這個時候message的Dep就收集到了三個依賴诲祸,這個依賴就是用來管理computed中message變化的而昨。
computed: { messageTransfer() { return this.message.split('').reverse().join(''); } }
-
圖示如下:一個屬性可能有多個依賴歌憨,每個響應(yīng)式數(shù)據(jù)都有一個Dep來管理它的依賴。
image.png
- Watcher
- Watcher是連接Observer和Compile的橋梁甲抖,Compile解析指令時會創(chuàng)建一個對應(yīng)的Watcher并綁定update方法 , 添加到Dep對象上惧眠。
Dep 如何收集依賴
- Object.defineProperty
function defineReactive (obj, key, val) { let Dep; // 依賴 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: () => { console.log('我被讀了于个,我要不要做點(diǎn)什么好?'); // 被讀取了厅篓,將這個依賴收集起來 Dep.depend(); // 本次新增 return val; }, set: newVal => { if (val === newVal) { return; } val = newVal; // 被改變了捶码,通知依賴去更新 Dep.notify(); // 本次新增 console.log("數(shù)據(jù)被改變了,通知所有的wather去調(diào)用update!"); } }) }
什么是依賴 ? (Watcher)
Watcher就是類似觀察者的角色档押,比如message就有三個觀察者祈纯,當(dāng)message變化,就通知這三個觀察者粒没,他們就去執(zhí)行各自需要做的變化 watcher.update()簇爆。
-
可以推測出爽撒,Watcher必須要有的2個方法硕勿。一個就是通知變化厕妖,另一個就是被收集起來到Dep中去。
class Watcher { addDep() { // 我這個Watcher要被Observer塞到Dep里去了~~ }, update() { // Dep通知我更新呢~~ }, }
總結(jié)
Vue響應(yīng)式原理的核心就是Observer软能、Dep举畸、Watcher。
Observer中進(jìn)行響應(yīng)式的綁定跋核,在數(shù)據(jù)被讀的時候砂代,觸發(fā)get方法,執(zhí)行Dep來收集依賴刻伊,也就是收集Watcher椒功。
在數(shù)據(jù)被改的時候,觸發(fā)set方法丁屎,通過對應(yīng)的所有依賴(Watcher)旱眯,去執(zhí)行更新。比如watch和computed就執(zhí)行開發(fā)者自定義的回調(diào)方法共虑。