scope, $rootScope,$RootScopeProvider - acelan86/angular GitHub Wiki
$RootScopeProvider,$rootScope的提供者
function $RootScopeProvider() {
...
this.$get = ['$injector', '$exceptionHandler', '$parse',
function( $injector, $exceptionHandler, $parse) {
function Scope() { ... } //Scope声明
...
$rootScope = new Scope(); //实例
...
return $rootScope;
}
]
}
Scope对象声明
angular中的Scope对象使用function方式定义
从全局来看这里的Scope对象声明其实只是为了实例$rootScope服务的,后面生成的子作用域都是通过$rootScope.$new()产生,形成以$rootScope为根的Scope链, 对全局暴露的是$RootScopeProvider, 它拥有$get方法,获取$rootScope
function Scope() {
this.$id = nextUid(); //指定uid
//从这里看scope就是一个双向链表结构
this.$$phase = this.$parent =
this.$$watchers = //检测变化回调函数数组
this.$$nextSibling =
this.$$prevSibling =
this.$$childHead =
this.$$childTail =
null;
this['this'] = this.$root = this;
this.$$destroyed = false;
this.$$asyncQueue = []; //所有需要异步处理的事件数组
this.$$listeners = {};
this.$$isolateBindings = {};
}
Scope的实例方法
Scope.prototype = {
//创建子作用域
$new: function(isolate) { ... },
//检测数据变化回调函数注册方法
$watch: function(watchExp, listener, objectEquality) { ... },
//遍历watchers执行脏数据回调
$digest: function() { ... },
//作用域销毁方法
$destroy: function() {
...
},
//执行表达式方法
$eval: function(expr, locals) { ... },
//异步表达式处理方法,其实就是放入异步回调数组。。
$evalAsync: function(expr) { ... },
//从外部调用angular表达式时使用的方法,比如DOM事件,XHR,setTimeout,或者第三方插件处理的表达式
$apply: function(expr) { ... },
//为scope添加监听事件
$on: function(name, listener) { ... },
//触发scope上的事件
$emit: function(name, args) { ... },
//广播一个事件
$broadcast: function(name, args) { ... }
};
Scope.prototype.$new方法
//这货在这的用法感觉像是一个child的工厂方法
Scope.prototype.$new = function(isolate) {
var Child,
child;
...
if (isolate) {
//隔离作用域,直接由Scope对象实例,不形成链
child = new Scope();
child.$root = this.$root;
} else {
//非隔离作用域,这里真简单暴力
Child = function() {};
Child.prototype = this; //继承
child = new Child();
child.$id = nextUid();
}
child['this'] = child;
child.$$listeners = {};
child.$parent = this;
child.$$asyncQueue = [];
child.$$watchers = child.$$nextSibling = child.$$childHead = child.$$childTail = null;
child.$$prevSibling = this.$$childTail;
//Scope链的连接,就是链表操作
if (this.$$childHead) {
this.$$childTail.$$nextSibling = child;
this.$$childTail = child;
} else {
this.$$childHead = this.$$childTail = child;
}
return child;
}
Scope.prototype.$digest方法
Scope.prototype.$digest = function() {
var watch, value, last,
watchers,
asyncQueue,
length,
dirty, ttl = TTL,
next, current, target = this,
watchLog = [],
logIdx, logMsg;
beginPhase('$digest'); //rootScope.$$phase = '$digest';声明处于digest阶段,注意这里是从rootScope上声明
do {
dirty = false;
current = target;
do {
asyncQueue = current.$$asyncQueue;
//先处理当前scope实例上的异步队列中的表达式
while(asyncQueue.length) {
try {
current.$eval(asyncQueue.shift());
} catch (e) {
$exceptionHandler(e);
}
}
//执行$$watchers中的监测数据回调函数,没啥复杂,你懂的,找到当前监测数据值与上次值equal对比,dirty就执行回调方法,循环完所有的watcher就ok了
if ((watchers = current.$$watchers)) {
length = watchers.length;
while (length--) {
try {
//每一个watcher知道我关注的是那个model name
//通过watch.get(currentscope)获取当前scope中这个mode name的值,watch.last中存放上次值
//watch.fn中保存dirty的处理方法
watch = watchers[length];
if ((value = watch.get(current)) !== (last = watch.last) &&
!(watch.eq
? equals(value, last)
: (typeof value == 'number' && typeof last == 'number'
&& isNaN(value) && isNaN(last)))) {
dirty = true;
watch.last = watch.eq ? copy(value) : value;
watch.fn(value, ((last === initWatchVal) ? value : last), current);
//这段没看明白干啥?ttl(time to live?)
if (ttl < 5) {
logIdx = 4 - ttl;
if (!watchLog[logIdx]) watchLog[logIdx] = [];
logMsg = (isFunction(watch.exp))
? 'fn: ' + (watch.exp.name || watch.exp.toString())
: watch.exp;
logMsg += '; newVal: ' + toJson(value) + '; oldVal: ' + toJson(last);
watchLog[logIdx].push(logMsg);
}
}
} catch (e) {
$exceptionHandler(e);
}
}
}
// 深度优先遍历scope链,确保走完所有由当前节点出发的分支链
if (!(next = (current.$$childHead || (current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
} while ((current = next));
if(dirty && !(ttl--)) {
clearPhase();
throw Error(TTL + ' $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: ' + toJson(watchLog));
}
} while (dirty || asyncQueue.length);
//rootScope.$$phase = null; 退出处理阶段
clearPhase();
}
Scope.prototype.$watch
Scope.prototype.$watch: function(watchExp, listener, objectEquality) {
var scope = this,
get = compileToFn(watchExp, 'watch'),
array = scope.$$watchers,
watcher = {
fn: listener,
last: initWatchVal,
get: get,
exp: watchExp,
eq: !!objectEquality
};
// in the case user pass string, we need to compile it, do we really need this ?
if (!isFunction(listener)) {
var listenFn = compileToFn(listener || noop, 'listener');
watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
}
if (!array) {
array = scope.$$watchers = [];
}
// we use unshift since we use a while loop in $digest for speed.
// the while loop reads in reverse order.
array.unshift(watcher);
//这里居然返回function。。。逆天看不懂。。等后面看
return function() {
arrayRemove(array, watcher);
};
}