angularJS之$watch、$digest和$apply方法
2013-10-31 23:09
323 查看
最近项目上使用了比较多的angular JS,一直都对它感觉比较陌生,总觉得有点反直觉,这段时间,准备下定决心弄明白,这个框架到底是怎么一回事,以及它的工作原理,生命周期……一点一点的啃完它吧。首先,让我们先来看看$watch、$digest、$apply这三个方法吧!
$watch(watchExpression, listener, objectEquality)
从表格中可以看到,watchExpression和listener可以是一个string,也可以是一个function(scope)。该表达式在每次调用了$digest方法之后都会重新算值,如果返回值发生了改变,listener就会执行。在判断newValue和oldValue是否相等时,会递归的调用angular.equals方法。在保存值以备后用的时候调用的是angular.copy方法。listener在执行的时候,可能会修改数据从而触发其他的listener或者自己直到没有检测到改变为止。Rerun Iteration的上限是10次,这样能够保证不会出现死循环的情况。
$watch的基本结构如下:
$digest()
该方法会触发当前scope以及child scope中的所有watchers,因为watcher的listener可能会改变model,所以$digest方法会一直触发watchers直到不再有listener被触发。当然这也有可能会导致死循环,不过angular也帮我们设置了上限10!否则会抛出“Maximum iteration limit exceeded.”。
通常,我们不在controller或者directive中直接调用$digest方法,而是调$apply方法,让$apply方法去调用$digest方法。
如何调用该方法呢?
$apply(exp)
个人理解,$apply方法就是将$digest方法包装了一层,exp是可选参数,可以是一个string,也可以是function(scope)。伪代码(来自官方文档)如下:
$apply方法使得我们可以在angular里面执行angular框架之外的表达式,比如说:浏览器DOM事件、setTimeout、XHR或其他第三方的库。由于我们要在angular框架内调用,我们必须得准备相应的scope。调用方式如下:
$watch、$digest、$apply是如何与视图的更新相关联的呢?
directive给$scope上的一个model注册$watch来监视它的变化,listener会去更新DOM元素的值。
directive给DOM中的一些元素注册event handler,它们会取得DOM中元素的值,然后更新到$scope上的model中去。它也会触发$apply或者$digest。
当你通过框架更新了$scope上model的值,比如说:$http.get(),当它完成后也会触发$digest方法。
$digest会去检查directive注册的$watch,发现值被修改就会触发相关联的handler,然后更新DOM元素。
至于angular js为什么要这么做,请看我上一篇博客angular js之scope.$apply方法。
$watch
当$scope上的值发生变化时,尽量在directive中使用$watch去更新DOM。
尽量不要再controller中使用$watch方法,它会增加测试的复杂度,而且也不必要。可以使用scope上的方法去更新被改变的值。
$digest、$apply
在directive中使用$digest/$apply使angular知道一个异步请求完成后的变化,比如说DOM Event。
在service中使用$digest/$apply使angular知道一个异步操作已经完成,比如说WebSocket、或者第三方的库。
尽量不要再controller中使用$digest/$apply,这样的话测试起来会比较困难。
===============================================================================
关于angular.equals方法
该方法支持value types,regular expressions、arrays、objects。官方文档写的很清楚:
Two objects or values are considered equivalent if at least one of the following is true:
Both objects or values pass === comparison.
Both objects or values are of the same type and all of their properties are equal by comparing them with angular.equals.
Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
Both values represent the same regular expression (In JavasScript, /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual representation matches).
During a property comparison, properties of function type and properties with names that begin with $ are ignored.
Scope and DOM Window objects are being compared only by identify (===).
$watch(watchExpression, listener, objectEquality)
Param | Type | Details |
watchExpression | function() string | Expression that is evaluated on each $digest cycle. A change in the return value triggers a call to the listener. string: Evaluated as expression function(scope): called with current scope as a parameter. |
listener (optional) | function() string | Callback called whenever the return value of the watchExpressionchanges. string: Evaluated as expression function(newValue, oldValue, scope): called with current and previous values as parameters. |
objectEquality (optional) | boolean | Compare object for equality rather than for reference. |
$watch的基本结构如下:
//$scope.$watch(<function/expression>, <handler>); $scope.$watch('foo', function(newVal, oldVal) { console.log(newVal, oldVal); }); //or $scope.$watch(function() { return $scope.foo; }, function(newVal, oldVal) { console.log(newVal, oldVal); });
$digest()
该方法会触发当前scope以及child scope中的所有watchers,因为watcher的listener可能会改变model,所以$digest方法会一直触发watchers直到不再有listener被触发。当然这也有可能会导致死循环,不过angular也帮我们设置了上限10!否则会抛出“Maximum iteration limit exceeded.”。
通常,我们不在controller或者directive中直接调用$digest方法,而是调$apply方法,让$apply方法去调用$digest方法。
如何调用该方法呢?
$scope.$digest();
$apply(exp)
Param | Type | Details |
exp (optional) | string function() | An angular expression to be executed. string: execute using the rules as defined in expression. function(scope): execute the function with current scope parameter. |
function $apply(expr) { try { return$eval(expr); } catch(e) { $exceptionHandler(e); } finally { $root.$digest(); } }
$apply方法使得我们可以在angular里面执行angular框架之外的表达式,比如说:浏览器DOM事件、setTimeout、XHR或其他第三方的库。由于我们要在angular框架内调用,我们必须得准备相应的scope。调用方式如下:
$scope.$apply('foo = "test"'); //or $scope.$apply(function(scope) { scope.foo = 'test'; }); //or $scope.$apply(function(){ $scope.foo = 'test'; });
$watch、$digest、$apply是如何与视图的更新相关联的呢?
directive给$scope上的一个model注册$watch来监视它的变化,listener会去更新DOM元素的值。
directive给DOM中的一些元素注册event handler,它们会取得DOM中元素的值,然后更新到$scope上的model中去。它也会触发$apply或者$digest。
当你通过框架更新了$scope上model的值,比如说:$http.get(),当它完成后也会触发$digest方法。
$digest会去检查directive注册的$watch,发现值被修改就会触发相关联的handler,然后更新DOM元素。
至于angular js为什么要这么做,请看我上一篇博客angular js之scope.$apply方法。
$watch
当$scope上的值发生变化时,尽量在directive中使用$watch去更新DOM。
尽量不要再controller中使用$watch方法,它会增加测试的复杂度,而且也不必要。可以使用scope上的方法去更新被改变的值。
$digest、$apply
在directive中使用$digest/$apply使angular知道一个异步请求完成后的变化,比如说DOM Event。
在service中使用$digest/$apply使angular知道一个异步操作已经完成,比如说WebSocket、或者第三方的库。
尽量不要再controller中使用$digest/$apply,这样的话测试起来会比较困难。
===============================================================================
关于angular.equals方法
该方法支持value types,regular expressions、arrays、objects。官方文档写的很清楚:
Two objects or values are considered equivalent if at least one of the following is true:
Both objects or values pass === comparison.
Both objects or values are of the same type and all of their properties are equal by comparing them with angular.equals.
Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
Both values represent the same regular expression (In JavasScript, /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual representation matches).
During a property comparison, properties of function type and properties with names that begin with $ are ignored.
Scope and DOM Window objects are being compared only by identify (===).
相关文章推荐
- cocos2d-x精灵内存管理
- IOS越狱开发(三)------DEB生成和apt建立
- IOS越狱开发(三)------DEB生成和apt建立
- 驱动保护中的ObjectType_Callback探索
- iOS7: 如何获取不变的UDID
- android中的drawable资源
- Cocos2d-x学习之---自定义图标(带触摸事件)
- Cocos2d-x学习之---自定义图标(带触摸事件)
- 微信不是淘宝杀手 腾讯难满足冲动性消费
- windows8 APP开发的远程调试
- ArcGIS for android以任意点为中心放大缩小
- Android 对Layout_weight属性完全解析以及使用ListView来实现表格
- 微信公共平台入门
- Android高效加载大图、多图解决方案,有效避免程序内存溢出现象
- 记录cocos2d-html5与cocosd-x jsb中遇到的坑
- Android ListView的理解(一)
- android 上传图片
- Android4.2.2 Gallery2源码分析(4)——GLCanvas.java
- Android Service完全解析,关于服务你所需知道的一切(上)
- IBM Security AppScan V8.8 portfolio 发布