提及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变化的次数