如果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;
}