AngularJs 臟值檢查及其相關


今天突然就想寫寫$digest和$apply,這些都是臟值檢查的主體內容。

先以普通js來做一個簡單的監控例子吧:

  var div = ducoment.getElementById("myDiv");
      div.addEventListener("click",function(e){
        console.log(e);
    })

在這里,我們給一個div綁定了個點擊事件,並且給這個綁定事件一個回調函數。這里我們就是給了這個div一個監聽,當監聽到有點擊事件發生在此div上,則執行該回調函數。

Angular的$watch也是這樣的效果。拿ngModel為例:
  in html:     <input ng-model="value" />
  in controller.js:     $scope.value = "Hello World";
我們只要改變input里的值,在controller里對應的$scope.value也會隨之發生相同的變化。這里就是給$watch列表添加了一個監控函數,從而做到這個效果的。
$watch列表就是給所有綁定到同一$scope對象的UI元素添加一個監控函數到$watch列表里。
$watch列表會觸發$digest循環,並且在$digest循環中通過“臟值檢查”機制進行解析。
臟值檢查
什么是臟值檢查?簡單來說,就是Angular檢查模型的值是否發生了變化,而程序還沒對該變化進行同步的機制。Angular將會通過臟值檢查遍歷整個$watch列表,只要當中的某個值發生了變化,應用就會退回到$digest循環中,直到檢測到這個值不再發生任何變化,然后再啟用新值並且繼續遍歷$watch列表。整個$watch列表循環后,且其中值都不再變化了,那么整個應用程序的model也就趨於穩定了,這時候才在View渲染該有的數據。
這里有個報錯需要注意,也是挺多人會遇到且提出的問題,到底是什么錯誤呢,發上來秀秀,想必大家不會陌生~

  Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

$digest循環運行10次,Angular就會拋出這個異常,同時停止$digest循環。而10這個次數可以在config里面注入$rootScopeProvider服務並且配置:

  $rootScopeProvider.digestTtl(15);

這時候,錯誤就變成了:

  Error: [$rootScope:infdig] 15 $digest() iterations reached. Aborting!

哈哈,小伙伴們肯定會說:你個小賤人,不就是換個數值重新報錯么.... 好吧,那么你上去看看本獸說的出現這個錯誤的原因,不就可以根據問題來解決了么 -。-
上面那個服務是用於配置當值不穩定的時候,$digest循環幾次自動跳出循環的,部分場景可能會用得到。
關於$watch函數以及相關的使用,可以移步本獸的另一篇文章,url請狂戳這里:$watch 
$digest循環是臟值檢查機制的主體,那么$digest怎么玩呢?
自動進入$digest我們已經知道了,比如$scope的$watch列表中值發生變化,則觸發$digest循環。
那么手動召喚我們偉大的$digest循環呢?我們可以直接召喚$digest (#01),也可以集齊一只$apply來召喚$digest。
$apply()函數在框架外部讓表達式在Angular上下文內部執行。好吧,這個確實聽起來比較繞...
下面來一段$apply的使用代碼吧:

  <div ng-app="Demo" ng-controller="testCtrl as ctrl">
      <my-dir count="ctrl.count"></my-dir>{{ctrl.count}}
  </div>
  (function(){
     angular.module('Demo', [])
     .directive("myDir",myDir)
     .controller('testCtrl',testCtrl);
     function myDir(){
       return{
         restrict:'AECM',
         template:'<input type="button" value="click me" />',
         scope:{count:"="},
          link: function(scope, element, attrs) {
           element.bind('click', function() {
              scope.count++;
              scope.$apply();
           });
         }
       }  
     };
     function testCtrl() {
         this.count = 0;
     }
  }());

順便也扯下,該在啥時使用$apply
Angular提供的可用於視圖中任意指令都可調用$apply(),比如:ng-click,ng-change等等。
還有一些Angular內置的服務會調用$digest()。比如:$http服務(在XHR請求完成並觸發更新返回的promise中會調用$apply())、使用$timeout()。
在我們使用第三方框架時或在自己寫的指令當中使用。比如:jQuery(Angular不建議在controller內操作DOM,DOM操作應該在Directive中使用,所以jQuery代碼也請寫在指令里吧),上面的代碼(也是在指令中使用)。

關於$apply vs $digest ,請移步另一篇Github譯文:( 譯、持續更新 ) JavaScript小技巧介紹  #01 - AngularJs: $digest vs $apply 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM