谈谈angularjs中$watch,$apply,$digest
http://my.oschina.net/Nealyang/blog/552069
摘要
angularJs中$watch,$apply和$digest的使用和原理
大家都是到angularJS中非常屌的一个性能,数据双向绑定,这就意味着view中的数据发生任何变化的时候,这个变化也会相应的反映到scope上,也就是说scope的模型会动态更新。所以有时候我们的需求可能是要监控摸个model的变化,下面就简单的说下这个操作以及实现原理 $watch <html> <head> <scriptsrc='./lib.angular.min.js'></script> </head> <bodyng-app='watch'> <inputng-model='name'type='text'/> <div>changecount:{{count}}</div> <script> angular.module('watch',[]) .run(['$rootScope',function($rootScope){ $rootScope.count=0; $rootScope.name='Alfred'; $rootScope.$watch('name',function(){ $rootScope.count++; }) }]); </script> </body> </html>
上面这个代码就是用来监控name的变化的,每次当我们在input输入框中输入一个值的时候,$rootScope中的count就会对应的+1; 在angularJS的内部,每当我们对name的值进行修改的时候,angularJS内部中的$digest就会被调用一次,(下面在详细的说$digest的原理),并在运行结束之后检查我们用$watch来监控的模型,如何和上一次执行$digest之前相比发生变化了,则执行$watch中的回调函数。 然而!!!在我们实际的开发中,仅仅实现对一个原始类型的数据监控是远远不能够满足所需的,对于原始类型的数据,如果我们使用了一次赋值操作,则这个原始类型的数据变量会真正的别赋值一次,然而对于引用类型的变量,进行赋值时,仅仅是将赋值的变量指向了这个引用类型。 <html> <head> <scriptsrc='./lib.angular.min.js'></script> </head> <bodyng-app='watch'> <divng-repeat='iteminitems'> <inputng-model='item.a'/><span>{{item.a}}</span> </div> <div>changecount:{{count}}</div> <script> angular.module('watch',function($rootScope){ $rootScope.count=0; $rootScope.items=[ {"a":1},{"a":2},{"a":3},{"a":4} ] $rootScope.$watch('items',function(){ $rootScope.count++; }) }]); </script> </body> </html>
在这个栗子中我们就会发现,不管我们怎么改变其中的值,count都不会发生变化的。而这个就是我们上面说那样,在说明这个之前,我们在说明下$watch的第三个参数,一般$watch函数的前两个参数是必传的(监控对象,回调函数),第三个参数默认为false,这样的话我们进行的监控叫做引用监控,这个意思就是监控对象的应用没有发生变化的时候就不算对象发生了变化,具体的来说,上面的例子,就算items的属性发生了变化,只要items的引用没有发生变化,$watch就都当做没有看见,但是比如讲一个数组赋值给items时,这个时候$watch就看不下去了(给你阳光你就灿烂了还)。 当然值得提一下的是:为什么第三个参数加个true,这么方便了我们还不加呢?!当然是牵涉到性能的问题啦!全等监控运行起来的时候是先监控到整个对象,然后在每一次吧$diges跑起来之前先用angualr.copy()将整个对象先拷贝一遍之后再调用angular.equal()方法来进行比较,所以这一监控可能会消耗大量的资源! 在angularJS 1.1.4又出来了一个$watchCollection()方法,专门来监控数组集合的,他的性能介于引用监控和全等监控之间,它不会对数组的每一项内容 进行监控,而是当数组的pop和push时候做出反应。具体的栗子咱就不多赘述了。 下面谈一谈$apply watcher={
fn:listener,//监听回调函数
last:initWatchVal,//上一状态值
get:get,//取得监听的值
exp:watchExp,//监听表达式
eq:!!objectEquality//要不要比较引用
};
那么我们什么时候去进行脏检查呢? <!--lang:js--> functionCtrl($scope){ $scope.message="Waiting2000msforupdate"; setTimeout(function(){ $scope.message="Timeoutcalled!";//AngularJSunawareofupdateto$scope},2000);}
简单说dom上永远都不会显示Timeout called 下面说下$apply的使用注意事项吧 然而这个脏检查有事怎么检查的呢?? 暂且就说这么多吧,说多了也迷糊,很多都是需要自己去实际应用和体会的 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |