angularJS $watch $digest $apply
一 简介
AngularJS提供了一个非常酷的特性叫做双向数据绑定(Two-way Data Binding),这个特性大大简化了我们的代码编写方式。数据绑定意味着当View中有任何数据发生了变化,那么这个变化也会自动地反馈到scope的数据上,也即意味着scope模型会自动地更新。类似地,当scope模型发生变化时,view中的数据也会更新到最新的值。那么AngularJS是如何做到这一点的呢?当你写下表达式如{{ aModel }}时,AngularJS在幕后会为你在scope模型上设置一个watcher,它用来在数据发生变化的时候更新view。
二 $watch
1.什么是$watch
$scope对象上的$watch方法会给Angular事件循环内的每个$digest调用装配一个脏值检查,如果在表达式上检测到变化,Angular总是会返回$digest循环。
也就是说,$watch代表的就是对数据源的监听,当数据源发生变化,就会触发第二个参数的回调函数。
2.使用
$watch函数本身接受两个必要参数和一个可选的参数:
$scope.$watch(‘aModel’, function(newValue, oldValue) {
//update the DOM with newValue
},true);
第一个参数:可以是一个作用域对象的属性,或者是一个函数,在$digest循环中的每个$digest调用都会涉及到它。如果是一个字符串,Angular会在$scope上下文中对它求值。
第二个参数:作为回调的监听器函数,它智慧在第一个参数的当前值与先前值不相等时调用。
第三个参数:true/false,默认为false,主要用于第一个参数为引用型的情况下。
3.举例:
<body>
<input ng-model=‘name‘ type=‘text‘/>
<div>change count: {{count}}</div>
<script>
angular.module(‘myApp‘,[])
.run([‘$rootScope‘,function($rootScope){
$rootScope.count = 0;
$rootScope.name = ‘hcc‘;
$rootScope.$watch(‘name‘,function(){
$rootScope.count++;
})
}]);
</script>
</body>
用$watch来对$rootScope中的name进行监视,并在它发生变化的时候将$rootScope中的count属性增加1。因此,每当我们对name进行一次修改时,下面显示的count数字就会增加1。
然而,我们在实际运用中常常不只是对一个原始类型的属性进行监视,还可能对集合进行监视。对于原始类型,如果我们使用了一个赋值操作,则这个原始类型变量会“真正的”被进行一次复制,然而对于引用类型,在进行赋值时,仅仅是将赋值的变量指向了这个引用类型。因此如果要对一个引用类型,尤其是在实际运用中常见的对象数组进行监视时,情况就不一样了。
<body>
<div hg-repeat=‘item in items‘>
<input ng-model=‘item.a‘/><span>{{item.a}}</span>
</div>
<div>change count: {{count}}</div>
<script>
angular.module(‘myApp‘,[])
.run([‘$rootScope‘,function($rootScope){
$rootScope.count = 0;
$rootScope.items = [
{ "a": 1 },
{ "a": 2 },
{ "a": 3 },
{ "a": 4 }
]
$rootScope.$watch(‘items‘,function(){
$rootScope.count++;
},true)
}]);
</script>
</body>
在angular 1.1.4版本之后,添加了一个$watchCollection()方法来针对数组(也就是集合)进行监视,它的性能介于全等监视和引用监视二者之间,即它并不会对数组中每一项的属性进行监视,但是可以对数组的项目的增减做出反应。
在这里只需将$rootScope.$watch改成$rootScope.$watchCollection即可:
$rootScope.$watchCollection(‘items‘,function() {
$rootScope.count++;
})
对集合的操作,推荐使用这种方式。
三 $digest和$apply
1.在调用了$scope.$digest()后,$digest循环就开始了。假设你在一个ng-click指令对应的handler函数中更改了scope中的一条数据,此时AngularJS会自动地通过调用$digest()来触发一轮$digest循环。当$digest循环开始后,它会触发每个watcher。这些watchers会检查scope中的当前model值是否和上一次计算得到的model值不同。如果不同,那么对应的回调函数会被执行。调用该函数的结果,就是view中的表达式内容会被更新。
AngularJS并不直接调用$digest(),而是调用$scope.$apply(),后者会调用$rootScope.$digest()。因此,一轮$digest循环在$rootScope开始,随后会访问到所有的children scope中的watchers。
正常情况下,在angular上下文中,修改数据源就会自动触发。$apply只是把$digest做了一次封装,来提供手动触发,那么为什么需要手动触发呢。因为如果是不在angular上下文的情况下,如浏览器DOM事件,setTimeout执行,这种情况下,angular无法获取到事件,所以,通过apply来手动触发一下,在apply的参数中去修改数据源。
2.举例:
<body ng-app=“myApp”>
<div ng-controller=“MessageController”>
Delayed Message: {{message}}
</div>
</body>
angular.module(‘myApp’,[]).controller(‘MessageController’, function($scope) {
$scope.getMessage = function() {
setTimeout(function() {
$scope.message = ‘Fetched after 3 seconds';
console.log(‘message:’+$scope.message);
}, 2000);
}
$scope.getMessage();
});
通过运行这个例子,你会看到过了两秒钟之后,控制台确实会显示出已经更新的model,然而,view并没有更新。原因也许你已经知道了,就是我们忘了调用$apply()方法。因此,我们需要修改getMessage()。
angular.module(‘myApp’,[]).controller(‘MessageController’, function($scope) {
$scope.getMessage = function() {
setTimeout(function() {
$scope.$apply(function() {
//wrapped this within $apply
$scope.message = ‘Fetched after 3 seconds';
console.log(‘message:’ + $scope.message);
});
}, 2000);
}
$scope.getMessage();
});
angularJS $watch $digest $apply的更多相关文章
- 理解Angular中的$apply()以及$digest()
$apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的 ...
- 深入理解Angular中的$Apply()以及$Digest()
$apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的 ...
- angularJS中的$apply(),$digest(),$watch()
$apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的 ...
- $watch How the $apply Runs a $digest
作者:junyuecao | 发表于 8-8 13:39 | 最后更新时间:8-9 02:34 原文地址:http://angular-tips.com/blog/2013/08/watch-how- ...
- $apply() $digest()
理解Angular中的$apply()以及$digest() <!DOCTYPE html> <html> <head> <meta charset=&quo ...
- angularjs现学现记之—$apply()和$digest()
angularjs的双向数据绑定是个重要的特性,它让我们的代码简洁了许多,然而它又是如何知道数据发生了变化并改变页面的呢.最近看了一篇介绍觉得十分有用 首先,在angularjs中是有$watch事件 ...
- Angular DirtyChecking(脏值检查) $watch, $apply, $digest
Dirty Checking (脏值检查) Digest cycle and $scope Digest cycle and $scope First and foremost, AngularJS ...
- --@angularjs--理解Angular中的$apply()以及$digest()
$apply() 和 $digest() 在 AngularJS 中是两个核心概念,但是有时候它们又让人困惑.而为了了解 AngularJS 的工作方式,首先需要了解 $apply() 和 $dige ...
- (网页)理解Angular中的$apply()以及$digest()
转自CSDN: 工作有问题上CSDN上转转. $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$ ...
- Angular1.x DirtyChecking(脏值检查) $watch, $apply, $digest
Dirty Checking (脏值检查) Digest cycle and $scope Digest cycle and $scope First and foremost, AngularJS ...
随机推荐
- iOS sizeWithFont 过期 is deprecated
原文: http://www.cnblogs.com/A--G/p/4819189.html iOS 2.0之后 sizeWithFont就被弃用了: //计算textview 高度 - (float ...
- 【转】iOS-Core-Animation-Advanced-Techniques(五)
原文:http://www.cocoachina.com/ios/20150105/10829.html 图层时间和缓冲 图层时间 时间和空间最大的区别在于,时间不能被复用 -- 弗斯特梅里克 在上面 ...
- js获取标签的几种方式
一:id获取(全部浏览器兼容) document.getElementById(""); <body> <div id="box">&l ...
- Debug your C# project more efficiently
I am a very beginner working with C# and Visual Studio 2013. When I debug my project, I always reope ...
- 子树大小平衡树(Size Balanced Tree,SBT)操作模板及杂谈
基础知识(包括但不限于:二叉查找树是啥,SBT又是啥反正又不能吃,平衡树怎么旋转,等等)在这里就不(lan)予(de)赘(duo)述(xie)了. 先贴代码(数组模拟): int seed; int ...
- 将日期和时间作为 struct tm型的值直接向二进制文件进行读写
#include <stdio.h> #include <time.h> char data_file[]="D:\\%\\datetime.dat"; v ...
- struts2文件上传,文件类型 allowedTypes
struts2文件上传,文件类型 allowedTypes 1 '.a' : 'application/octet-stream', 2 '.ai' : 'application/postscript ...
- Chrome 中的彩蛋——T-Rex
今天,从网页上看到chrome的T-Rex的彩蛋,眨眼间完了10分钟.分享出来,只是好玩. 当 Chrome 无法连接到互联网时,或者上着网突然掉线,刷新页面时报错,我们都会看到T-Rex的身影,没错 ...
- ASP.NET MVC轻教程 Step By Step 3 ——使用ViewBag
在上一节我们创建了与Index动作方法对应的Index视图,那么Index动作方法该如何向Index视图传送数据呢?其中一个方法是使用ViewBag(视图包).让我们试试看. 在Index动作方法中添 ...
- net programming guid
Beej's Guide to Network Programming Using Internet Sockets Brian "Beej Jorgensen" Hallbeej ...