雙向綁定是angular的大亮點,而後支撐它的就是髒檢測。一直對髒檢測都有一些理解,卻沒有比較系統的概念。html
如下是我閱讀網上博文以及angular高級程序設計的理解與總結。app
接收指導與批評。函數
將原對象賦值一份快照。在某個時間,遍歷比較這個對象和快照(新舊值),若是不同就執行執行某些操做。spa
1.不會檢查全部的對象。當對象被綁定到html會檢查,手動$scope.$watch()的會檢查。檢查的手段就是爲這些對象建立(watcher)對象。並push到(watcher隊列) 2.不會檢查全部的屬性。只要被綁定的屬性纔會被註冊。 在angular程序初始化時,會將綁定的對象的屬性添加爲監聽對象(watcher),也就是說一個對象綁定了N個屬性,就會添加N個watcher。設計
angular註冊watcher對象雙向綁定
angualr會爲每個綁定到DOM的對象/對象的屬性,建立一個watcher對象,(使用$scope.$watch()方法也會建立),watcher對象有好幾個屬性,(下面是筆者理解抽象出來的,並非真的屬性名)code
watch = { name:'', //當前的watch 對象 觀測的數據名,鎖定監聽的是什麼 getNewValue:function($scope){ //獲取監聽屬性的最新值 ... return newValue; }, listener:function(newValue,oldValue){ // 先比較新值與舊值判斷是否繼續執行,通常負責使用新值更新DOM頁面,也能夠是$watch方法註冊的回調函數 ... } }
$$watchers的watcher屬性截圖htm
$scope.$$watchers隊列對象
每個建立好的watcher對象會被push到各自的controller做用域的$scope.$$watchers隊列裏面。
髒檢測就是遍歷watchers的過程。blog
髒檢測經過兩個方法觸發:$digest(), $apply()
$digest:是遍歷當前做用域以及其子做用域的$$watchers隊列,並執行其listener。
$apply:是對$digest()的封裝。接受一個函數參數(包含脫離angular環境的邏輯,須要卻不會本身觸發髒檢測, 因此$apply幫他觸發一下。),$apply在執行了參數函數以後自動調用 $rootScope.$digest (就是從更做用於開始遍歷每個$scope.$$watchers隊列)
若是你對本身的邏輯比較清楚,能夠不使用$apply,改用$scope.$digest(),只遍歷當前與其子做用域。不用從rootScope開始。
若是不是很瞭解邏輯,建議仍是使用$apply()從rootScope開始,避免須要更新的值沒有被更新,而且$apply會把參數函數放在try...catch裏面,若是邏輯發生錯誤。會把錯誤傳給$exceptionHandler service來處理。
$scope.data = 0; $scope.data2 = 0; // code 1 setInterval(function() { $scope.$apply(function() { $scope.data++; console.log('first:', $scope.data) }); }, 2000); // code 2 setInterval(function() { $scope.data2++; console.log('second:', $scope.data2) $scope.$apply(); // 對比code1,少了try...catch // $scope.$digest(); // 只遍歷當前及其子做用域的$$watchers隊列 },2000)
一次髒檢測中$digest()執行的次數?
在一個髒檢測中,digest至少會執行兩次。
由於某一個監聽屬性的listener可能會改變另外一個監聽屬性的值。所以,angular須要在一次$digest()以後判斷這一輪digest中時候有沒有屬性發生變化並執行了listener,若是有,angular必須再次調用$digest();當已經連續觸發了10次$digest(),若還有屬性發生變化,angular就會認爲你的邏輯錯了並console報告。所以在$scope.$watch時要本身多加註意理解好邏輯問題。
何時會觸發髒檢測?
好像很多人有一個誤區。angular是定時執行髒檢測的!!!!(我以前還問過,angular設置多久執行一次髒檢測,無言以對)
angular並非定時的。會觸發髒檢測的有如下:
回頭想一想,若是是定時的,怎麼會有脫離angualr環境的說法呢?