angular核心$watch,$digest,$apply之间的联系
来源:互联网 发布:37诸神黄昏进阶数据 编辑:程序博客网 时间:2024/06/04 18:34
浏览器事件发生时,会在浏览器的上下文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
$digest是将$watch和$apply绑定在一起的魔法胶水函数。从高级别来看,$digest将计算作用域(及作用域的孩子)中所有的$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个监视器。
除了默认调用之外,有时候我们也可以手动调用$digest循环,记住只有angular事件,也即是angular content处理的事件才会调用$digest循环,如果在window环境处理的事件,比如setTimeout,Jquery事件,则不会调用$digest循环,如果我们不手动调用,则视图不会随模型数据变化更新。
angular.module('app', function ($scope) {setTimeout(function () {$scope.arr = [1];$scope.$digest(); //setTimeout中手动调用$digest});});
$apply
$appy组成了双向数据绑定的另一边,它将通知angular某些东西改变了,$watch表达式的值应该重新计算。实际上$apply总是会默认调用$digest循环。它的官方伪代码如下:
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()。
我们可以把函数传入$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++; });})
阅读全文
0 0
- angular核心$watch,$digest,$apply之间的联系
- Angular关于$watch,$apply 以及 $digest的工作原理及相关知识点
- 浅谈angular.js中实现双向绑定的方法$watch $digest $apply
- angular JS之$watch、$digest和$apply方法
- angualr-$apply,$digest,$watch的理解
- watch(),$digest()和$apply()
- angular.js的$apply 和 $digest()
- Angular($digest和$apply)
- AngularJS: $watch() , $digest() and $apply()
- 双向绑定---angular之watch、apply、digest原理深入分析(源码分析)
- Angular中的$apply()以及$digest()
- Angular之$apply和$digest
- 全面解析Angular中$Apply()及$Digest()的区别
- 理解Angular的$ apply()和$ digest()
- Angular.js之手动调用$apply()以及$digest()的理解
- angular中$scope.$apply和$scope.$digest的区别
- 【Angular】理解Angular中的$apply()以及$digest()
- angularJS--apply() 、digest()和watch()方法
- Android动画实现详解
- ubuntu修改默认文本编辑器为vim
- 【转】【译】fetch用法说明
- 利用WinRAR的自解压格式将Cocos2d-x项目代码打包成.exe文件
- 递归算法典例
- angular核心$watch,$digest,$apply之间的联系
- 2017 计蒜之道 初赛 第一场 阿里的新游戏(找规律,几何,模拟)
- HDFS 指令(三)touchz,test,text,stat,appendToFile,checksum,count,chmod
- memmove和memcpy函数的区别及实现
- Java开学学习实录1
- TypeScript笔记
- java实现验证码类生成中文验证码
- Mac pro使用的那些坑(二)git的安装和git终端打开
- java登录验证码实现代码