淺析$watch ,$apply 和 $digest (Angular篇)

來源:互聯網
上載者:User

標籤:images   隊列   檢查   也會   互動   put   facebook   不能   img   

 前言

瞭解過angular的人都知道,angular的一大特性就是雙向資料繫結。所謂雙向資料繫結,即當View中有任何資料發生了變化,其對應的 scope模型會自動地更新,而當scope模型發生變化時,view中的資料也會更新到最新的值。那麼它是怎麼做到的呢,$watch是怎麼工作的,$apply 和 $digest又是用於做什麼的,下面我們來探討一下。

瀏覽器事件和angular擴充

在標準的瀏覽器流程中,當事件被觸發時(比如點擊一個按鈕),瀏覽器會執行該事件的回呼函數,執行回調時會進入Javascript執行環境。當回調執行完畢,就退出Javascript執行環境,然後重新整理視圖。Angular在此基礎上建立了一個自己的執行環境及事件處理迴圈,只有在AngularJS執行環境中啟動並執行操作,才能享受到AngularJS提供的資料繫結,異常處理,資源管理等功能和服務。Angular和瀏覽器事件迴圈互動如下:

 

下面用個例子來解析一下angular執行過程:

html

<button ng-click="changeData()">點擊</button><p>{{data}}</p>

 

controller

$scope.changeData=function(){    $scope.data=1;}

 

(1)上面的“點擊”按鈕綁定到angular的點擊事件,當使用者點擊按鈕時,angular會把changeData函數封裝並傳入到$scope.$apply(),通過調用$scope.$apply(changeData),進入到angular執行環境,在angular環境中執行changeData。

(2)AngularJS進入$digest迴圈。這個迴圈是由兩個小迴圈組成的: $evalAsync隊列和$watch列表。執行changeData,changeData中修改了$scope.data;同時,angular遍曆整個$watch列表,檢測到$watch 列表中的data值的變化,然後再次啟動一輪$digest 迴圈;

(3)直到檢測到$watch 列表不再有任何變化後,AngularJS的$digest迴圈結束,離開AngularJS和Javascript的執行環境。

(4)瀏覽器把改變的資料data進行重渲染。

$watch

當我們在UI元素中綁定一個$scope對象時,就會往$watch list裡面添加一個$watch,對於所有綁定給同一$scope對象的UI元素,也只會添加一個$watch到$watch列表中。看如下代碼

(1)

html

<input ng-model="name" type="text" placeholder="Your name"><input ng-model="age"  type="text" placeholder="Your age"><h1>Hello {{name}}</h1>

這裡有兩個一樣的$scope.name,還有個$scope.pass,所以在$watch list裡面加入兩個$watch。

(2)

html

<p>{{a}}</p>

 

controller

$scope.a=‘dataA‘;$scope.a=‘dataB‘;

這裡雖然在controller中定義了兩個$scope對象,但是只有一個$scope.a是綁定到UI元素中的,所以只在$watch list裡面加入一個$watch。

 

$digest

當瀏覽器接收到可以被angular 執行環境處理的事件時(比如ng-click、ng-keypress),$digest迴圈就會觸發。這個迴圈是由兩個小的迴圈組合起來的。一個處理evalAsync隊列,另一個處理$watch隊列。

在$digest迴圈中,angular會遍曆完整個$watch列表,所有的$watch都檢查完後只要有任何一個$watch的值發生變化,這個迴圈就會再次觸發,繼續遍曆$watch列表直到檢測到不再有任何變化。為什麼要再次運行這一迴圈?因為如果你更新了$watch列表中某個用於更新另一個值的值,Angular將檢測不到更新,除非再次運行這個迴圈。看如下例子

html

<button ng-click="changeNum()">點擊</button><p>{{num1}}</p><p>{{num2}}</p>

 

controller

$scope.num1=1;$scope.num2=$scope.num1+2;$scope.changeNum=function(){    $scope.num1=2;}

當我們點擊按鈕的時候,改變了num1的資料,由於num2資料是受num1資料影響的,如果不再次啟動$digest迴圈,Angular將檢測不到num2資料的更新。

這就是所謂的髒值檢測。這樣就能夠保證每個model都已經不會再變化。記住如果迴圈超過10次的話,它將會拋出一個異常,防止無限迴圈。 當$digest迴圈結束時,DOM相應地變化。

 

$apply

$apply()函數可以使事件進入到Angular的執行環境中執行。那麼問題來了,什麼時候該用$apply(),什麼時候不該用呢?

Angular提供的可用於視圖中的任意指令(比如ng-click、ng-keypress)、Angular內建的服務(比如$http、$timeout等),使用的時候都會自動調用$apply()。所以,我們不用再去手動調用$apply()了;

當我們手動處理事件,使用第三方架構(比如jQuery、Facebook API),或者調用setTimeout(),他們並沒有調用$apply(),所以事件不能在angular執行環境中執行,$digest迴圈無法檢測到事件中對視圖資料的更改,視圖無法更新。這個時候,我們就需要手動調用$apply();

 

淺析$watch ,$apply 和 $digest (Angular篇)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.