首先基于我的理解分析Dep构造函数
/**
* Remove an item from an array.
*/
function remove (arr, item) {
if (arr.length) {
var index = arr.indexOf(item);
if (index > -1) {
return arr.splice(index, 1)
}
}
}
以上是Dep的原型方法中removeSub部分用到的函数。remove函数接收两个参数,数组和元素。逻辑就是数组中存在这个元素,就将它移除,并封装成数组返回。
// The current target watcher being evaluated.
// This is globally unique because only one watcher
// can be evaluated at a time.
Dep.target = null;
var targetStack = [];
function pushTarget (target) {
targetStack.push(target);
Dep.target = target;
}
function popTarget () {
targetStack.pop();
Dep.target = targetStack[targetStack.length - 1];
}
以上Dep的原型方法中depend用到的Dep.target。看作者注释,目前正在被评估的目标watcher,这在作用域范围内是独一无二的,因为同一时刻只有一个watcher能被评估。 所以Dep.target是啥,就是现在在评估的watcher。targetStack是一个栈,pushTarget和popTarget就是实现栈的方法,Dep.target对应的就是栈顶的watcher。还有一个点,是Dep.target用的的API addDep。
/**
* Add a dependency to this directive.
*/
Watcher.prototype.addDep = function addDep (dep) {
var id = dep.id;
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id);
this.newDeps.push(dep);
if (!this.depIds.has(id)) {
dep.addSub(this);
}
}
};
由以上可以看出,这个API是watcher原型链上的方法。看作者的注释, 向这个watcher添加依赖。watcher的分析不在本文内,以后找时间分析。
/**
* A dep is an observable that can have multiple
* directives subscribing to it.
*/
var Dep = function Dep () {
this.id = uid++;
this.subs = [];
};
Dep.prototype.addSub = function addSub (sub) {
this.subs.push(sub);
};
Dep.prototype.removeSub = function removeSub (sub) {
remove(this.subs, sub);
};
Dep.prototype.depend = function depend () {
if (Dep.target) {
Dep.target.addDep(this);
}
};
Dep.prototype.notify = function notify () {
// stabilize the subscriber list first
var subs = this.subs.slice();
if (!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[i].update();
}
};
首先看作者注释,dep是一个可被观测的对象,可以有多个watcher去订阅它。所以dep是什么,dep是收集watcher的数组,并在原型上定义了对watcher进行管理的一组方法。那么什么是watcher?在Vue1.0中,它具有细粒度的特征,当数据发生改变时,通知到每一个用到数据的地方,那么,就会在一定程度上对性能造成影响。在Vue2.0后,作者采用了中等粒度的设计方式,当数据发生改变时,通知到watcher,再由watcher通知到具体关联的依赖集体。
/**
* A watcher parses an expression, collects dependencies,
* and fires callback when the expression value changes.
* This is used for both the $watch() api and directives.
* /
以上是watcher的注释的意思是watcher是一个订阅者,收集依赖(collects dependences),并且在表达式发生变化时触发回调,这个逻辑同时适用于$watch api以及指令。什么是依赖,我的理解是具体用到数据的地方。
经由上面的分析,dep是什么,dep的addSub、removeSub以及depend方法是干啥的就已经很清楚了。dep是收集watcher的数组,是一个订阅者列表,addSub是把watcher压入数组,removeSub是移除指定的watcher,而depend就是修改watcher(这一部分需要看watcher api的源码,不在本文讨论范围内)。再来看notify是干啥的。
if (!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; });
}
以上作者考虑到了同步的场景,在同步的情况下以watcher的id进行排序。也就是说在同步的情况下以watcher的id顺序进行通知。(为什么要这样做,正在思考中)所以notify是干啥的,它是通知watcher更新的。