function(watchExp, listener, objectEquality) {
var scope = this,
// 将可能的字符串编译成fn
get = compileToFn(watchExp, 'watch'),
array = scope.$$watchers,
watcher = {
fn: listener,
last: initWatchVal, // 上次值记录,方便下次比较
get: get,
exp: watchExp,
eq: !!objectEquality // 配置是引用比较还是值比较
};
lastDirtyWatch = null;
if (!isFunction(listener)) {
var listenFn = compileToFn(listener || noop, 'listener');
watcher.fn = function(newVal, oldVal, scope) {listenFn(scope);};
}
if (!array) {
array = scope.$$watchers = [];
}
// 之所以使用unshift不是push是因为在 $digest 中watchers循环是从后开始
// 为了使得新加入的watcher也能在当次循环中执行所以放到队列最前
array.unshift(watcher);
// 返回unwatchFn, 取消监听
return function deregisterWatch() {
arrayRemove(array, watcher);
lastDirtyWatch = null;
};
}
// 进入$digest循环打上标记,防止重复进入
beginPhase('$digest');
lastDirtyWatch = null;
// 脏值检查循环开始
do {
dirty = false;
current = target;
// asyncQueue 循环省略
traverseScopesLoop:
do {
if ((watchers = current.$$watchers)) {
length = watchers.length;
while (length--) {
try {
watch = watchers[length];
if (watch) {
// 作更新判断,是否有值更新,分解如下
// value = watch.get(current), last = watch.last
// value !== last 如果成立,则判断是否需要作值判断 watch.eq?equals(value, last)
// 如果不是值相等判断,则判断 NaN的情况,即 NaN !== NaN
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发生改变
lastDirtyWatch = watch;
// 缓存last值
watch.last = watch.eq ? copy(value, null) : value;
// 执行listenerFn(newValue, lastValue, scope)
// 如果第一次执行,那么 lastValue 也设置为newValue
watch.fn(value, ((last === initWatchVal) ? value : last), current);
// ... watchLog 省略
if (watch.get.$$unwatch) stableWatchesCandidates.push({watch: watch, array: watchers});
}
// 这边就是减少watcher的优化
// 如果上个循环最后一个更新的watch没有改变,即本轮也没有新的有更新的watch
// 那么说明整个watches已经稳定不会有更新,本轮循环就此结束,剩下的watch就不用检查了
else if (watch === lastDirtyWatch) {
dirty = false;
break traverseScopesLoop;
}
}
} catch (e) {
clearPhase();
$exceptionHandler(e);
}
}
}
// 这段有点绕,其实就是实现深度优先遍历
// A->[B->D,C->E]
// 执行顺序 A,B,D,C,E
// 每次优先获取第一个child,如果没有那么获取nextSibling兄弟,如果连兄弟都没了,那么后退到上一层并且判断该层是否有兄弟,没有的话继续上退,直到退到开始的scope,这时next==null,所以会退出scopes的循环
if (!(next = (current.$$childHead ||
(current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
} while ((current = next));
// break traverseScopesLoop 直接到这边
// 判断是不是还处在脏值循环中,并且已经超过最大检查次数 ttl默认10
if((dirty || asyncQueue.length) && !(ttl--)) {
clearPhase();
throw $rootScopeMinErr('infdig',
'{0} $digest() iterations reached. Aborting!\n' +
'Watchers fired in the last 5 iterations: {1}',
TTL, toJson(watchLog));
}
} while (dirty || asyncQueue.length); // 循环结束
// 标记退出digest循环
clearPhase();
function(expr) {
if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length) {
$browser.defer(function() {
if ($rootScope.$$asyncQueue.length) {
$rootScope.$digest();
}
});
}
this.$$asyncQueue.push({scope: this, expression: expr});
}
if (!$rootScope.$$phase && !$rootScope.$$asyncQueue.length)
$browser.defer 就是通过调用 setTimeout 来达到改变执行顺序
$browser.defer(function() {
//...
});
function (exp) {
queue.push({scope: this, expression: exp});
this.$digest();
}
scope.$evalAsync(fn1);
scope.$evalAsync(fn2);
// 这样的结果是
// $digest() > fn1 > $digest() > fn2
// 但是实际需要达到的效果:$digest() > fn1 > fn2
while(asyncQueue.length) {
try {
asyncTask = asyncQueue.shift();
asyncTask.scope.$eval(asyncTask.expression);
} catch (e) {
clearPhase();
$exceptionHandler(e);
}
lastDirtyWatch = null;
}
function(isolate) {
var ChildScope,
child;
if (isolate) {
child = new Scope();
child.$root = this.$root;
// isolate 的 asyncQueue 及 postDigestQueue 也都是公用root的,其他独立
child.$$asyncQueue = this.$$asyncQueue;
child.$$postDigestQueue = this.$$postDigestQueue;
} else {
if (!this.$$childScopeClass) {
this.$$childScopeClass = function() {
// 这里可以看出哪些属性是隔离独有的,如$$watchers, 这样就独立监听了,
this.$$watchers = this.$$nextSibling =
this.$$childHead = this.$$childTail = null;
this.$$listeners = {};
this.$$listenerCount = {};
this.$id = nextUid();
this.$$childScopeClass = null;
};
this.$$childScopeClass.prototype = this;
}
child = new this.$$childScopeClass();
}
// 设置各种父子,兄弟关系,很乱!
child['this'] = child;
child.$parent = this;
child.$$prevSibling = this.$$childTail;
if (this.$$childHead) {
this.$$childTail.$$nextSibling = child;
this.$$childTail = child;
} else {
this.$$childHead = this.$$childTail = child;
}
return child;
}
function(name, listener) {
var namedListeners = this.$$listeners[name];
if (!namedListeners) {
this.$$listeners[name] = namedListeners = [];
}
namedListeners.push(listener);
var current = this;
do {
if (!current.$$listenerCount[name]) {
current.$$listenerCount[name] = 0;
}
current.$$listenerCount[name]++;
} while ((current = current.$parent));
var self = this;
return function() {
namedListeners[indexOf(namedListeners, listener)] = null;
decrementListenerCount(self, 1, name);
};
}
var current = this;
do {
if (!current.$$listenerCount[name]) {
current.$$listenerCount[name] = 0;
}
current.$$listenerCount[name]++;
} while ((current = current.$parent));
function(name, args) {
var empty = [],
namedListeners,
scope = this,
stopPropagation = false,
event = {
name: name,
targetScope: scope,
stopPropagation: function() {stopPropagation = true;},
preventDefault: function() {
event.defaultPrevented = true;
},
defaultPrevented: false
},
listenerArgs = concat([event], arguments, 1),
i, length;
do {
namedListeners = scope.$$listeners[name] || empty;
event.currentScope = scope;
for (i=0, length=namedListeners.length; i<length; i++) {
// 当监听remove以后,不会从数组中删除,而是设置为null,所以需要判断
if (!namedListeners[i]) {
namedListeners.splice(i, 1);
i--;
length--;
continue;
}
try {
namedListeners[i].apply(null, listenerArgs);
} catch (e) {
$exceptionHandler(e);
}
}
// 停止传播时return
if (stopPropagation) {
event.currentScope = null;
return event;
}
// emit是向上的传播方式
scope = scope.$parent;
} while (scope);
event.currentScope = null;
return event;
}
function(name, args) {
var target = this,
current = target,
next = target,
event = {
name: name,
targetScope: target,
preventDefault: function() {
event.defaultPrevented = true;
},
defaultPrevented: false
},
listenerArgs = concat([event], arguments, 1),
listeners, i, length;
while ((current = next)) {
event.currentScope = current;
listeners = current.$$listeners[name] || [];
for (i=0, length = listeners.length; i<length; i++) {
// 检查是否已经取消监听了
if (!listeners[i]) {
listeners.splice(i, 1);
i--;
length--;
continue;
}
try {
listeners[i].apply(null, listenerArgs);
} catch(e) {
$exceptionHandler(e);
}
}
// 在digest中已经有过了
if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
(current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
}
event.currentScope = null;
return event;
}
if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
(current !== target && current.$$nextSibling)))) {
while(current !== target && !(next = current.$$nextSibling)) {
current = current.$parent;
}
}
$scope.names = ['igor', 'matias', 'misko', 'james'];
$scope.dataCount = 4;
$scope.$watchCollection('names', function(newNames, oldNames) {
$scope.dataCount = newNames.length;
});
expect($scope.dataCount).toEqual(4);
$scope.$digest();
expect($scope.dataCount).toEqual(4);
$scope.names.pop();
$scope.$digest();
expect($scope.dataCount).toEqual(3);
function(obj, listener) {
$watchCollectionInterceptor.$stateful = true;
var self = this;
var newValue;
var oldValue;
var veryOldValue;
var trackVeryOldValue = (listener.length > 1);
var changeDetected = 0;
var changeDetector = $parse(obj, $watchCollectionInterceptor);
var internalArray = [];
var internalObject = {};
var initRun = true;
var oldLength = 0;
// 根据返回的changeDetected判断是否变化
function $watchCollectionInterceptor(_value) {
// ...
return changeDetected;
}
// 通过此方法调用真正的listener,作为代理
function $watchCollectionAction() {
}
return this.$watch(changeDetector, $watchCollectionAction);
}
function $watchCollectionInterceptor(_value) {
newValue = _value;
var newLength, key, bothNaN, newItem, oldItem;
if (isUndefined(newValue)) return;
if (!isObject(newValue)) {
if (oldValue !== newValue) {
oldValue = newValue;
changeDetected++;
}
} else if (isArrayLike(newValue)) {
if (oldValue !== internalArray) {
oldValue = internalArray;
oldLength = oldValue.length = 0;
changeDetected++;
}
newLength = newValue.length;
if (oldLength !== newLength) {
changeDetected++;
oldValue.length = oldLength = newLength;
}
for (var i = 0; i < newLength; i++) {
oldItem = oldValue[i];
newItem = newValue[i];
bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
if (!bothNaN && (oldItem !== newItem)) {
changeDetected++;
oldValue[i] = newItem;
}
}
} else {
if (oldValue !== internalObject) {
oldValue = internalObject = {};
oldLength = 0;
changeDetected++;
}
newLength = 0;
for (key in newValue) {
if (hasOwnProperty.call(newValue, key)) {
newLength++;
newItem = newValue[key];
oldItem = oldValue[key];
if (key in oldValue) {
bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
if (!bothNaN && (oldItem !== newItem)) {
changeDetected++;
oldValue[key] = newItem;
}
} else {
oldLength++;
oldValue[key] = newItem;
changeDetected++;
}
}
}
if (oldLength > newLength) {
changeDetected++;
for (key in oldValue) {
if (!hasOwnProperty.call(newValue, key)) {
oldLength--;
delete oldValue[key];
}
}
}
}
return changeDetected;
}
if (oldValue !== internalArray) {
oldValue = internalArray;
oldLength = oldValue.length = 0;
changeDetected++;
}
if (oldLength !== newLength) {
changeDetected++;
oldValue.length = oldLength = newLength;
}
for (var i = 0; i < newLength; i++) {
oldItem = oldValue[i];
newItem = newValue[i];
bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
if (!bothNaN && (oldItem !== newItem)) {
changeDetected++;
oldValue[i] = newItem;
}
}
if (oldValue !== internalObject) {
oldValue = internalObject = {};
oldLength = 0;
changeDetected++;
}
newLength = 0;
for (key in newValue) {
if (hasOwnProperty.call(newValue, key)) {
newLength++;
newItem = newValue[key];
oldItem = oldValue[key];
if (key in oldValue) {
bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
if (!bothNaN && (oldItem !== newItem)) {
changeDetected++;
oldValue[key] = newItem;
}
} else {
oldLength++;
oldValue[key] = newItem;
changeDetected++;
}
}
}
if (oldLength > newLength) {
changeDetected++;
for (key in oldValue) {
if (!hasOwnProperty.call(newValue, key)) {
oldLength--;
delete oldValue[key];
}
}
}
function $watchCollectionAction() {
if (initRun) {
initRun = false;
listener(newValue, newValue, self);
} else {
listener(newValue, veryOldValue, self);
}
// trackVeryOldValue = (listener.length > 1) 查看listener方法是否需要oldValue
// 如果需要就进行复制
if (trackVeryOldValue) {
if (!isObject(newValue)) {
veryOldValue = newValue;
} else if (isArrayLike(newValue)) {
veryOldValue = new Array(newValue.length);
for (var i = 0; i < newValue.length; i++) {
veryOldValue[i] = newValue[i];
}
} else {
veryOldValue = {};
for (var key in newValue) {
if (hasOwnProperty.call(newValue, key)) {
veryOldValue[key] = newValue[key];
}
}
}
}
}
$eval: function(expr, locals) {
return $parse(expr)(this, locals);
},
$apply: function(expr) {
try {
beginPhase('$apply');
return this.$eval(expr);
} catch (e) {
$exceptionHandler(e);
} finally {
clearPhase();
try {
$rootScope.$digest();
} catch (e) {
$exceptionHandler(e);
throw e;
}
}
}
机械节能产品生产企业官网模板...
大气智能家居家具装修装饰类企业通用网站模板...
礼品公司网站模板
宽屏简约大气婚纱摄影影楼模板...
蓝白WAP手机综合医院类整站源码(独立后台)...苏ICP备2024110244号-2 苏公网安备32050702011978号 增值电信业务经营许可证编号:苏B2-20251499 | Copyright 2018 - 2025 源码网商城 (www.ymwmall.com) 版权所有