
注意右側(cè)的調(diào)用隊(duì)列 進(jìn)行初始化的時(shí)候 this._init() 初始化的時(shí)候調(diào)用 initState() initData() initData中會(huì)調(diào)用根節(jié)點(diǎn)的observe 將數(shù)據(jù)變成響應(yīng)式對(duì)象

// initData()中調(diào)用根節(jié)點(diǎn)的 observe
// observe data
observe(data, true /* asRootData */);
observe只處理 對(duì)象
*/
function observe (value, asRootData) {
// 不是對(duì)象 或 是 VNode就返回 這是遞歸的出口
if (!isObject(value) || value instanceof VNode) {
return
}
var ob;
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
// 這是一個(gè)observe的自己
ob = value.__ob__;
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
// 創(chuàng)建Observer的對(duì)象
ob = new Observer(value);
}
if (asRootData && ob) {
ob.vmCount++;
}
return ob
}
// Observer 對(duì)象
var Observer = function Observer (value) {
this.value = value;
// watch的管理者 收集依賴 和派發(fā)更新中使用
this.dep = new Dep();
this.vmCount = 0;
// 定義不可枚舉的值 作為標(biāo)識(shí)
def(value, '__ob__', this);
if (Array.isArray(value)) {
if (hasProto) {
protoAugment(value, arrayMethods);
} else {
copyAugment(value, arrayMethods, arrayKeys);
}
this.observeArray(value);
} else {
this.walk(value);
}
};
// 如果是對(duì)象 每個(gè)對(duì)象中調(diào)用 defineReactive
Observer.prototype.walk = function walk (obj) {
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
defineReactive$$1(obj, keys[i]);
}
};
// 如果是數(shù)組 遞歸調(diào)用observe每一個(gè)對(duì)象 所以都會(huì)走到 defineReactive
Observer.prototype.observeArray = function observeArray (items) {
for (var i = 0, l = items.length; i < l; i++) {
observe(items[i]);
}
};
下面來(lái)看看defineReactive的代碼
function defineReactive$$1 (
obj,
key,
val,
customSetter,
shallow
) {
// Dep是一個(gè)watch收集管理器
var dep = new Dep();
var property = Object.getOwnPropertyDescriptor(obj, key);
// 如果是不可枚舉的 就直接return 所以不可變更對(duì)象可以使用Object.frezone
if (property && property.configurable === false) {
return
}
// ...
var childOb = !shallow && observe(val);
// 利用es5的defineProperty 劫持getter/setter getter的時(shí)候 通過(guò)dep.depend()建立依賴收集 setter的時(shí)候dep.notify() 派發(fā)更新
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
set: function reactiveSetter (newVal) {
var value = getter ? getter.call(obj) : val;
if (getter && !setter) { return }
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = !shallow && observe(newVal);
dep.notify();
}
});
}
// 派發(fā)更新 執(zhí)行堆棧dep.notify() watch.update() queueWatcher(this) flushSchedulerQueue() 執(zhí)行watcher的run方法 如下源碼所示
dep.notify
Dep.prototype.notify = function notify () {
// stabilize the subscriber list first
var subs = this.subs.slice();
if (process.env.NODE_ENV !== 'production' && !config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort(function (a, b) { return a.id - b.id; });
}
for (var i = 0, l = subs.length; i < l; i++) {
// subs是一個(gè)watch的數(shù)組
subs[i].update();
}
};
/**
* Flush both queues and run the watchers.
*/
function flushSchedulerQueue () {
currentFlushTimestamp = getNow();
flushing = true;
var watcher, id;
// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
queue.sort(function (a, b) { return a.id - b.id; });
// do not cache length because more watchers might be pushed
// as we run existing watchers
for (index = 0; index < queue.length; index++) {
watcher = queue[index];
if (watcher.before) {
watcher.before();
}
id = watcher.id;
has[id] = null;
watcher.run();
// in dev build, check and stop circular updates.
if (process.env.NODE_ENV !== 'production' && has[id] != null) {
circular[id] = (circular[id] || 0) + 1;
if (circular[id] > MAX_UPDATE_COUNT) {
warn(
'You may have an infinite update loop ' + (
watcher.user
? ("in watcher with expression \"" + (watcher.expression) + "\"")
: "in a component render function."
),
watcher.vm
);
break
}
}
}

Watcher.prototype.run = function run () {
if (this.active) {
var value = this.get();
if (
value !== this.value ||
// Deep watchers and watchers on Object/Arrays should fire even
// when the value is the same, because the value may
// have mutated.
isObject(value) ||
this.deep
) {
// set new value
var oldValue = this.value;
this.value = value;
if (this.user) {
try {
// 執(zhí)行用戶定義的watch的回調(diào) 參數(shù) newValue, oldValue
this.cb.call(this.vm, value, oldValue);
} catch (e) {
handleError(e, this.vm, ("callback for watcher "" + (this.expression) + """));
}
} else {
this.cb.call(this.vm, value, oldValue);
}
}
}
};
// mountComponent vue數(shù)據(jù)更新驅(qū)動(dòng)視圖的原理
// 定義渲染watcher watch的get函數(shù) 對(duì)應(yīng)的updateComponent 會(huì)改變視圖的變化 既是渲染watch初始化的時(shí)候被訂閱了對(duì)應(yīng)的響應(yīng)式數(shù)據(jù) 數(shù)據(jù)發(fā)生了變化會(huì)觸發(fā)這個(gè)視圖更新
// 這里會(huì)執(zhí)行 watch的run 會(huì)執(zhí)行 this.get 求職 會(huì)執(zhí)行 updateComponent函數(shù) 這樣會(huì)觸發(fā)視圖的更新
簡(jiǎn)單來(lái)說(shuō) 響應(yīng)數(shù)據(jù)發(fā)生變化 會(huì)觸發(fā) defineReactive 的setter中this.get 然后會(huì)觸發(fā) 渲染watch的updateComponent 從而達(dá)到視圖的變化
updateComponent = function () {
vm._update(vm._render(), hydrating);
};
}
// we set this to vm._watcher inside the watcher's constructor
// since the watcher's initial patch may call $forceUpdate (e.g. inside child
// component's mounted hook), which relies on vm._watcher being already defined
new Watcher(vm, updateComponent, noop, {
before: function before () {
if (vm._isMounted && !vm._isDestroyed) {
callHook(vm, 'beforeUpdate');
}
}
}, true /* isRenderWatcher */);
hydrating = false;
在vue中, 數(shù)據(jù)模型下的所有屬性,會(huì)被Vue使用Object.defineProperty(Vue3使用Proxy)進(jìn)行數(shù)據(jù)劫持代碼里。響應(yīng)式的機(jī)制是觀察者模式, 數(shù)據(jù)是被觀察的一方, 一旦發(fā)生變化, 通知所有的觀察者, 這樣觀察者可以做出響應(yīng), 當(dāng)觀察者為視圖的時(shí)候,會(huì)更新視圖。
Vue的響應(yīng)式系統(tǒng)的三個(gè)重要概念, Dep, Observer, Watcher.
Dep 調(diào)度中心-訂閱器
Dep是負(fù)責(zé)調(diào)度和訂閱watcher的 dep在getter觸發(fā)了dep.depend 收集依賴 在setter的時(shí)候 觸發(fā)了dep.notify 派發(fā)更新
Observer 發(fā)布者
Observer是發(fā)布者, 主要作用是vm初始化的時(shí)候, 調(diào)用defineReactive函數(shù), 使用Object.defineProperty方法對(duì)對(duì)象的每一個(gè)子屬性進(jìn)行數(shù)據(jù)劫持、監(jiān)聽(tīng), 就是為每個(gè)屬性添加上getter和setter, 使屬性變成響應(yīng)式。
Watcher-觀察者
Watcher 扮演的角色是訂閱者/觀察者,他的主要作用是為觀察屬性提供回調(diào)函數(shù)以及收集依賴,當(dāng)被觀察的值發(fā)生變化時(shí),會(huì)接收到來(lái)自調(diào)度中心Dep的通知,從而觸發(fā)回調(diào)函數(shù)。
而Watcher又分為三類(lèi),normal-watcher、 computed-watcher、 render-watcher。
normal-watcher:在組件鉤子函數(shù)watch中定義,即監(jiān)聽(tīng)的屬性改變了,都會(huì)觸發(fā)定義好的回調(diào)函數(shù)。
computed-watcher:在組件鉤子函數(shù)computed中定義的,每一個(gè)computed屬性,最后都會(huì)生成一個(gè)對(duì)應(yīng)的Watcher對(duì)象,但是這類(lèi)Watcher有個(gè)特點(diǎn):當(dāng)計(jì)算屬性依賴于其他數(shù)據(jù)時(shí),屬性并不會(huì)立即重新計(jì)算,只有之后其他地方需要讀取屬性的時(shí)候,它才會(huì)真正計(jì)算,即具備lazy(懶計(jì)算)特性。
render-watcher:每一個(gè)組件都會(huì)有一個(gè)render-watcher, 當(dāng)data/computed中的屬性改變的時(shí)候,會(huì)調(diào)用該Watcher來(lái)更新組件的視圖。
這三種Watcher也有固定的執(zhí)行順序,分別是:computed-render -> normal-watcher -> render-watcher。這樣就能盡可能的保證,在更新組件視圖的時(shí)候,computed 屬性已經(jīng)是最新值了,如果 render-watcher 排在 computed-render 前面,就會(huì)導(dǎo)致頁(yè)面更新的時(shí)候 computed 值為舊數(shù)據(jù)。
小結(jié)

Observer 負(fù)責(zé)將數(shù)據(jù)進(jìn)行攔截,Watcher 負(fù)責(zé)訂閱,觀察數(shù)據(jù)變化, Dep 負(fù)責(zé)接收訂閱并通知 Observer 和接收發(fā)布并通知所有 Watcher。