angular核心$watch,$digest,$apply之间的联系
浏览器事件发生时,会在浏览器的上下文window中执行,而angular有自己的上下文angular content,angular 事件在自己的上下文angular content中执行。
$watch
$watch组成了双向绑定的一边,在指定的表达式改变时调用,每个作用域都维护了一个监视器列表,被称为$scope.$$watchers。每次你绑定一些东西到你的UI上时你就会往$watch队列里插入一条$watch。
<ul>
<li ng-repeat="person in people">
{{person.name}} - {{person.age}}
</li>
</ul> app.controller('MainCtrl', function($scope) {
$scope.people = [
{name: 'a', age: 21},
{name: 'b', age: 25},
{name: 'c', age: 22}
];
});
这个例子生成了多少个$watch呢?ng-repeat一个,每个person两个,一共(2*3)+1=7个。
除了在视图上绑定数据创建一个$watch,还可以自定义$watch,但是有几点需要注意。
<body ng-controller="MainCtrl">
<input ng-model="user.name" />
Name updated: {{updated}} times.
</body> app.controller('MainCtrl', function($scope) {
$scope.user = { name: "Fox" }; $scope.updated = 0; $scope.$watch('user', function(newValue, oldValue) {
if (newValue === oldValue) { return; } //防止初始化时调用
$scope.updated++;
}, true); //第三个参数可选,如果设为true,则会比较对象的值,否则比较引用
});
当controller执行到这个$watch时,它会立即执行一次,所以我们加入了判断来防止第一个初始化的调用。其次是第三个参数,如果省略或者为false,则以上例子输入框的值改变之后,update的值不会改变,因为比较的user的引用。
每一个绑定到了UI上的数据都会生成一个$watch,那这些$watch是什么时候生成的呢?当我们的模版加载完毕时,也就是在linking阶段(Angular分为compile阶段和linking阶段),Angular解释器会寻找每个directive,然后生成每个需要的$watch。
$digest
var dirty = true;
var iterations = 0;
while (dirty && iterations++ < TIMES_TO_LOOP) {
dirty = false;
for (var i = 0; i < scope.watchers.length(); i++) {
var currentValue = scope.watchers[i].get();
if (currentValue != scope.watchers[i].oldValue) {
dirty = ture; //如果有数据改变了,则又$digest一次,直到没有数据改变
scope.watchers[i].callback(currentValue, scope.watchers[i].oldValue);
scope.watchers[i].oldValue = currentValue;
}
}
}
angular将TIMES_TO_LOOP(TTL)默认设为10,即$digest最多循环10次,超出后将抛出一个错误,防止无限循环,我们可以通过$rootScope服务和digestTtl函数改变这个值。
var app = angular.module('MyApp', [], function ($rootScopeProvider) {
$rootScopeProvider.digestTtl(15); //将TTL改为15
});
angular的内置指令会默认调用$digest,还有一点需要注意的是,UI中的所有指令都将创建至少一个监视器,所以angular的性能问题几乎总是因为以不合理的方式使用ngRepeat指令所引起的。如以上第一段代码,如果person对象达到10000个以上就会严重影响性能,实际上angular建议单个页面中不要使用超过2000个监视器。
angular.module('app', function ($scope) {
setTimeout(function () {
$scope.arr = [1];
$scope.$digest(); //setTimeout中手动调用$digest
});
});
$apply
function $apply(expr) {
try {
return$eval(expr);
} catch(e) {
$exceptionHandler(e);
} finally {
$root.$digest();
}
}
事件发生时是谁在决定事件是在window中执行还是angular content执行?答案是$apply(),例如内置的ngClick指令会默认调用$apply。那么什么时候需要我们手动调用$apply呢?和$digest一样,在angular里面执行angular框架之外的表达式,比如说:浏览器DOM事件、setTimeout、XHR或其他第三方的库时,这时就要求我们手动调用$apply()。
element.bind('click', function() {
scope.foo++;
scope.bar++;
scope.$apply(); //我们是在angular context的外面更新的数据,
//如果有发生错误,Angular永远不知道
});
element.bind('click', function() {
scope.$apply(function() { //把它封装进$apply里面,错误会传到angular里
scope.foo++; //例如一个服务器获取数据失败
scope.bar++;
});
})
angular核心$watch,$digest,$apply之间的联系的更多相关文章
- 谈谈Angular关于$watch,$apply 以及 $digest的工作原理
这篇文章主要是面向那些刚开始学AngularJs和想要了解数据绑定(data-binding)是怎么工作的, 如果你已经熟悉如何使用angularjs了,我强烈建议你不用阅读了. angularjs使 ...
- Angular:手动脏检查/$apply/$digest和监控对象/$watch
声明:借鉴好多chm资料.视频.PDF总结如下: 一.$apply的引入 View <div ng-app=""> <div ng-controller=&quo ...
- angular : direative :comunication 指令之间的通讯
在网络上可以找到多种指令之间的通讯 · $on,$emit,$boardcast (向上或向下冒泡) · 指令return的required (^)向上一个scope通讯,前提要先给scope一个na ...
- Angular学习笔记之组件之间的交互
1.@Input:可设置属性 当它通过属性绑定的形式被绑定时,值会“流入”这个属性. 在子组件中使用,例如:@Input()name:string 父组件定义宾亮,并在父组件的模板中绑定,例如: 子组 ...
- angular中对象与字符串之间的转换
1.angular 里 字符串与对象互转 angular.toJson();将字符串转成对象 angular.forJson(); 将字符串转成对象 2.angular 循环 <scr ...
- Angular 学习笔记——自定义指令之间的交互
<!DOCTYPE html> <html lang="en" ng-app="myApp"> <head> <met ...
- Vue与Angular以及React的三者之间的区别
1.与AngularJS的区别 相同点:都支持指令:内置指令和自定义指令:都支持过滤器:内置过滤器和自定义过滤器:都支持双向数据绑定:都不支持低端浏览器. 不同点:AngularJS的学习成本高,比如 ...
- Angular DirtyChecking(脏值检查) $watch, $apply, $digest
Dirty Checking (脏值检查) Digest cycle and $scope Digest cycle and $scope First and foremost, AngularJS ...
- angular $apply()以及$digest()讲解1
一些知名的批评和缺陷.他们都涉及到$digest loop(更新周期)中一个很常见的问题:如何在Angular之外更新$scope? 在哪调用 $apply? 更佳的做法是确保你是在$digest l ...
随机推荐
- 《Java I/O 从0到1》 - 第Ⅱ滴血 “流”
前言 <Java I/O 从0到1>系列上一章节,介绍了File 类,这一章节介绍的是IO的核心 输入输出.I/O类库常使用流这个抽象概念.代表任何有能力产出数据的数据源对象或者是有能力接 ...
- 对Java的初识
什么是计算机程序: 为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合.(简单来说就是记算机为完成某些功能生产的一系列有序指令集合); Java的来历: Java的初期开发早在 ...
- 云 MongoDB 优化让 LBS 服务性能提升十倍
欢迎大家前往腾讯云技术社区,获取更多腾讯海量技术实践干货哦~ 随着国内服务共享化的热潮普及,共享单车,共享雨伞,共享充电宝等各种服务如雨后春笋,随之而来的LBS服务定位问题成为了后端服务的一个挑战.M ...
- javascript篇-----数据类型
ECMAScript中一共有6种数据类型,其中包括5种基本数据类型(Undefined,Null,Boolean,Number,String)以及一种复杂数据类型(Object).[ES6增加多了一种 ...
- springmvc 格式化返回日期格式
<mvc:annotation-driven conversion-service="conversionService"> <mvc:message-conve ...
- 【转】elasticsearch的查询器query与过滤器filter的区别
很多刚学elasticsearch的人对于查询方面很是苦恼,说实话es的查询语法真心不简单- 当然你如果入门之后,会发现elasticsearch的rest api设计是多么有意思. 说正题,ela ...
- python之路第二篇(基础篇)
入门知识: 一.关于作用域: 对于变量的作用域,执行声明并在内存中存在,该变量就可以在下面的代码中使用. if 10 == 10: name = 'allen' print name 以下结论对吗? ...
- Python实战之双向队列deque/queue学习笔记及简单练习
['__add__', '__bool__', '__class__', '__contains__', '__copy__', '__delattr__', '__delitem__', '__di ...
- 学习笔记之08试用div做网页(滨院)-小作业
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Android Annotations(2)
AndroidAnnotations是一个开源框架,旨在加快Android开发的效率.通过使用它开放出来的注解api,你几乎可以使用在任何地方, 大大的减少了无关痛痒的代码量,让开发者能够抽身其外,有 ...