Angular數據綁定機制

關鍵詞:$watch, $digest, $apply, dirty-checking

1.Angular.js擴展瀏覽器的事件循環

瀏覽器持續等待例如用戶交互這樣的事件。當你在一個<input>標籤裏輸入字符以後,這個事件的回調函數在JS解釋器中執行了其包含的DOM操做,執行完畢後,瀏覽器響應地對DOM作出了變化。Angular拓展了這個事件循環,使它有時候成爲angular context 的執行環境。html

2.$watch list

$watch 能夠檢測model的變化。每當綁定一個數據到view上的時候,$watch隊列就會插入一條對應的$watch。例子以下:jquery

  • controller.js:
app.controller('MainCtrl', function($scope) {
  $scope.people = [...]; // 假設長度爲10
});
  • index.html:
<ul>
  <li ng-repeat="person in people">
      {{person.name}} - {{person.age}}
  </li>
</ul>

其中ng-repeat 生成了一個1個$watch,每一個person生成了2個$watch,總共是(1+2*10),21個$watch$watch的生成階段是模板加載完成,也就是linking階段。(angular分爲compilelinking階段),Angular會尋找每一個directive(上面的例子中ng-repeat和{{}}都屬於directive),而後生成每一個$watch瀏覽器

3.$digest 循環

當瀏覽器接收到angular context相關的事件時,$digest循環就會被觸發。它由2個小循環組成,1個處理evalAsync 隊列,另外一個處理$watch隊列。$digest進行循環時,將遍歷$watch隊列,查看是否有數據更新過,這種遍歷就叫作dirty-checkin(髒檢查),若是髒檢查發現有$watch更新,將會觸發新的髒檢查,直到全部的$watch都沒有更新。這樣就能保證每一個model都不會變化。app

髒檢查超過10次後會拋出異常防止無限循環。$digest循環結束後DOM會相應地發生變化。其實$digest從字面意義理解就像「消化」的過程同樣,逐漸地把全部養分($watch的變化)都吸取掉。函數

4.經過$apply 進入 angular context

$apply 決定事件是否進入angular context,使用angualr的自帶directive,好比ng-model,更改綁定的數據時,angular會將事件封裝到$apply中。好比,ng-model="name"的輸入框,輸入字符「w」,事件會調用,$apply("name='w';"),完成$scope中的數據更新。
調用第三方庫時的數據綁定
當在angular中調用jquery,並不能更新jquery綁定的數據,由於jquery沒有調用$apply,事件沒有進入angular context,致使$digest沒有執行。例子以下:spa

  • app.js
app.directive('clickable', function() {
    return {
      restrict: "E",
      scope: {
        count1: '=',
        count2: '='
      },
      template: '<ul style="background-color: lightblue"><li>{{count1}}</li><li>{{count2}}</li></ul>',
      link: function(scope, element, attrs) {
        element.bind('click', function() {
          scope.count1++;
          scope.count2++;
        });
      }
    }
});
app.controller('MainCtrl', function($scope) {
  $scope.count1= 0;
  $scope.count2= 0;
});

例子中,每次點擊該元素,預期count1和count2都會自增1,但實際沒有。其實$scope(ViewModel)已經改變,可是沒有強制執行$digest。修改click事件以下:rest

element.bind('click', function() {
  scope.$apply(function() {
      scope.foo++;
      scope.bar++;
  });
})

通過調用$apply實現了預期。code

5.總結

angular事件綁定機制以下圖:htm

圖片描述

相關文章
相關標籤/搜索