提及angular的數據綁定,你可能腦海立刻出現的就是這些$apply,$watch,$digest和髒值檢測這個名詞。javascript
正是因爲這些名詞背後的含義與功能組成了angular雙向數據綁定這一項強大的功能。html
首先來看一下一張圖,下面的來自angular官方的圖片。解釋了angular在數據綁定這部分是如何與瀏覽器的event loop機制作交互的。java
學習這個這個知識點以前,首先要理解下瀏覽器的event loop機制:angularjs
那如何從JS context切換到angular context呢,這個過程是怎麼實現的呢?ajax
答案就在angular 提供的$apply()函數:api
一般狀況下,你不須要本身調用$apply()函數,這是由於$apply()都已經被用來處理當前事件的相應指令執行過了。瀏覽器
只有當你使用自定義的事件回調或者是使用第三方類庫的回調時,才須要本身執行$apply()
服務器
下面的數據綁定過程來自angluar中文社區:網絡
scope.$apply(stimulusFn)
來進入AngularJS的執行上下文,這裏的stimulusFn是你但願在AngularJS執行上下文中執行的函數。stimulusFn()
,這個函數通常會改變應用的狀態。setTimeout(0)
來完成的。用setTimeout(0)
會有速度慢的問題。而且,由於瀏覽器是根據事件隊列按順序渲染視圖的,還會形成視圖的抖動。這裏你須要理解一些東西:app
1、$watch list
$watch list的操做發生在指令的link階段。
每次你須要把model上的數據綁定到你的view上時,$watch隊列就會插入一條對應的$watch
。$watch
就是監視的model裏數據變化的東西。
看一下下面的代碼:
<!DOCTYPE html> <html ng-app="app"> <head> <meta charset="utf-8"> <title></title> </head> <body> <div ng-controller="MainCtrl"> <input type="text" ng-model="name"/> <input type="text" ng-model="age"/> </div> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script type="text/javascript"> var app=angular.module('app',[]); app.controller('MainCtrl',function ($scope){ $scope.name='chenwei'; $scope.age='25'; $scope.text='world'; }); </script> </body> </html>
$scope上有三個對象:name,age,text。我把name和age綁定到了對應的輸入框上,text沒有綁定,這時候只會向$watch list上插入name和age兩個$watch。
2、$digest loop
$digest loop 有兩個子循環組成:一個處理evalAsync
隊列,另外一個處理$watch
隊列。
當瀏覽器接收到能夠被angular context
處理的事件時,$digest
循環就會觸發。
$digest 會去遍歷$watch list隊列,去檢測裏面的每一項$watch是否發生變化。
這裏須要注意的一點就是,若是有至少一個$watch更新過,這個循環就會再次觸發,直到全部的$watch
都沒有變化。這樣就可以保證每一個model都已經不會再變化。記住若是循環超過10次的話,它將會拋出一個異常,防止無限循環。 當$digest
循環結束時,DOM相應地變化。
3、定義本身的watch
$scope對象有一個可供開發者調用的$watch('watchName',fn,boolean)函數
看一個具體的代碼例子:
<!DOCTYPE html> <html ng-app="app"> <head> <meta charset="utf-8"> <title></title> </head> <body> <div ng-controller="MainCtrl"> <input type="text" ng-model="name"/> <input type="text" ng-model="age"/> <p>your name changed {{changeCount}} times</p> </div> <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script> <script type="text/javascript"> var app=angular.module('app',[]); app.controller('MainCtrl',function ($scope){ $scope.name='chenwei'; $scope.age='25'; $scope.text='world'; $scope.changeCount=0; $scope.$watch('name',function (newValue,oldValue){ if(newValue===oldValue){ return; } $scope.changeCount++; },true) }); </script> </body> </html>
上面的列子裏我用$watch函數去檢測name的值,一旦name的值發生變化,我就把它記錄下來,並經過changeCount亮來通知name變化的次數