如果digest遇到了死循环该如何处理
假设有两个watcher,在digest的时候互相更改对方的值,这会导致digest遇到死循环。于是应该给digest循环增加一个上限,达到上限却依然有脏值的时候,抛出异常:
Scope.prototype.$digest=function(){
var dirty;
var ttl = 10;
do {
dirty = this.$$digestOnce();
if(dirty&&!(ttl--)){
throw "digest次数到达上限依然不稳定"
}
} while (dirty);
}
如果有1000个watcher,每次digest都会把所有watcher跑一遍,效率太差了,怎么办
这个问题的解决思路是这样的:首先,我先记住上一次digest的最后一个脏watcher,比如有100个watcher,每次检测到脏watcher的时候,我都把这个watcher记录到一个变量里,这个变量叫做$$lastDirtyWatch
这个变量只记录一个watcher,就是最后遇到的那个脏watcher:
Scope.prototype.$$digestOnce=function(){
var self = this;
var oldValue,newValue,dirty;
for(var i=0;i<this.$$watchers.length;i++){
oldValue = this.$$watchers[i].last;
newValue = this.$$watchers[i].watchFn(self)
if(oldValue!=newValue){
this.$$lastDirtyWatch=this.$$watchers[i];//新加的一句话
this.$$watchers[i].last = newValue;
this.$$watchers[i].listenFn(newValue,oldValue,self);
dirty=true;
}
}
return dirty;
}
这样一来会有这样的效果,如果第49个watcher是脏的,那么this.$$lastDirtyWatch就指向第49个watcher,然后第55个是脏的,this.$$lastDirtyWatch就不再指向第49个watcher,而指向第55个watcher。
那么很显然:如果我们发现this.$$lastDirtyWatch这个指向第N个watcher,就说明N以后的watcher是干净的。
所以在digest循环的时候,每次检测watcher是否脏的时候,都去做一下对比,看看当前的watcher是不是this.$$lastDirtyWatch指向的那个watcher,如果是的话,就可以处理以后直接跳出循环了,因为后面的watcher都是干净的,没必要再循环一次了。
Scope.prototype.$$digestOnce=function(){
var self = this;
var oldValue,newValue,dirty;
for(var i=0;i<this.$$watchers.length;i++){
oldValue = this.$$watchers[i].last;
newValue = this.$$watchers[i].watchFn(self)
if(oldValue!=newValue){
this.$$lastDirtyWatch=this.$$watchers[i];
this.$$watchers[i].last = newValue;
this.$$watchers[i].listenFn(newValue,oldValue,self);
dirty=true;
}else{
if(this.$$watchers[i]===this.$$lastDirtyWatch){
return false;
}
}
}
return dirty;
}
网友评论