第一部分:$watch

$watch是一个scope函数,用于监听模型变化,当你的模型部分发生变化时它会通知你。

$watch(watchExpression, listener, objectEquality);

每个参数的说明如下:

  1. watchExpression:监听的对象,它可以是一个angular表达式如'name',或函数如function(){return $scope.name}。

  2. listener:当watchExpression变化时会被调用的函数或者表达式,它接收3个参数:newValue(新值), oldValue(旧值), scope(作用域的引用)

  3. objectEquality:是否深度监听,如果设置为true,它告诉Angular检查所监控的对象中每一个属性的变化. 如果你希望监控数组的个别元素或者对象的属性而不是一个普通的值, 那么你应该使用它

可参考:

http://yuankeqiang.lofter.com/post/8de51_1454f93

http://www.angularjs.cn/A0a6

官网:http://docs.angularjs.cn/api/ng/type/$rootScope.Scope

第二部分:$watch,$digest和$apply

最近项目上使用了比较多的angular JS,一直都对它感觉比较陌生,总觉得有点反直觉,这段时间,准备下定决心弄明白,这个框架到底是怎么一回事,以及它的工作原理,生命周期……一点一点的啃完它吧。首先,让我们先来看看watch、digest、$apply这三个方法吧!

  • $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. 

从表格中可以看到,watchExpression和listener可以是一个string,也可以是一个function(scope)。该表达式在每次调用了$digest方法之后都会重新算值,如果返回值发生了改变,listener就会执行。在判断newValue和oldValue是否相等时,会递归的调用angular.equals方法。在保存值以备后用的时候调用的是angular.copy方法。listener在执行的时候,可能会修改数据从而触发其他的listener或者自己直到没有检测到改变为止。Rerun Iteration的上限是10次,这样能够保证不会出现死循环的情况。
     $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.

个人理解,apply方法就是将digest方法包装了一层,exp是可选参数,可以是一个string,也可以是function(scope)。伪代码(来自官方文档)如下:

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是如何与视图的更新相关联的呢?
  1. directive给scope上的一个model注册watch来监视它的变化,listener会去更新DOM元素的值。
  2. directive给DOM中的一些元素注册event handler,它们会取得DOM中元素的值,然后更新到scope上的model中去。它也会触发apply或者$digest。
  3. 当你通过框架更新了scope上model的值,比如说:http.get(),当它完成后也会触发$digest方法。
  4. digest会去检查directive注册的watch,发现值被修改就会触发相关联的handler,然后更新DOM元素。

至于angular js为什么要这么做,请看我上一篇博客angular js之scope.$apply方法

  • $watch
  1. 当scope上的值发生变化时,尽量在directive中使用watch去更新DOM。
  2. 尽量不要再controller中使用$watch方法,它会增加测试的复杂度,而且也不必要。可以使用scope上的方法去更新被改变的值。
  • digest、apply
  1. 在directive中使用digest/apply使angular知道一个异步请求完成后的变化,比如说DOM Event。
  2. 在service中使用digest/apply使angular知道一个异步操作已经完成,比如说WebSocket、或者第三方的库。
  3. 尽量不要再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:

  1. Both objects or values pass === comparison.
  2. Both objects or values are of the same type and all of their properties are equal by comparing them with angular.equals.
  3. Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
  4. 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 (===).

来源:http://www.cnblogs.com/penghongwei/p/3400535.html

angular的$watch,$digest和$apply的更多相关文章

  1. Angular 学习笔记 :初识 $digest , $watch , $apply,浅析用法 。

    传统的浏览器事件循环 :浏览器本身一直在等待事件,并作出响应.如果你点击一个button或者在input 中输入字符,我们在 JS 中 监听这些事件并设定了回调函数,那么这些事件被触发以后,回调函数就 ...

  2. $watch、$digest、$apply

    $watch.$digest.$apply $watch 代表的就是对数据源的监听,当数据源发生变化,就会触发第二个参数的回调函数 $digest 代表触发一个数据源变化的事件 $apply 代表对于 ...

  3. angularJS之$watch、$digest和$apply方法

    最近项目上使用了比较多的angular JS,一直都对它感觉比较陌生,总觉得有点反直觉,这段时间,准备下定决心弄明白,这个框架到底是怎么一回事,以及它的工作原理,生命周期……一点一点的啃完它吧.首先, ...

  4. angularjs 中的$digest和$apply区别

    $digest和$apply 在Angular中,有$apply和$digest两个函数,我们刚才是通过$digest来让这个数据应用到界面上.但这个时候,也可以不用$digest,而是使用$appl ...

  5. 深入了解angularjs中的$digest与$apply方法,从区别聊到使用优化

     壹 ❀ 引 如果有人问,在angularjs中修改模型数据为何视图会同步更新呢,我想大多数人一定会回答脏检查(Dirty Checking)相关概念.没错,在angularjs中作用域(scope) ...

  6. angular核心$watch,$digest,$apply之间的联系

    浏览器事件发生时,会在浏览器的上下文window中执行,而angular有自己的上下文angular content,angular 事件在自己的上下文angular content中执行. $wat ...

  7. angular之 $watch 和$digest 和$apply和$observe的区别

    $watch 代表的就是对数据源的监听,当数据源发生变化,就会触发第二个参数的回调函数 $digest 代表触发一个数据源变化的事件 $apply 代表对于$digest的一个封装,他多了一个参数 . ...

  8. AngularJS中的digest循环$apply

    欢迎大家指导与讨论 : ) 前言 Angular会拓展这个标准的浏览器流程,创建一个Angular上下文.这个Angular上下文指的是运行在Angular事件循环内的特定代码,该Angular事件循 ...

  9. 理解Angular中的$apply()以及$digest()

    $apply()和$digest()在AngularJS中是两个核心概念,但是有时候它们又让人困惑.而为了了解AngularJS的工作方式,首先需要了解$apply()和$digest()是如何工作的 ...

随机推荐

  1. 主攻ASP.NET MVC4.0之重生:使用反射获取Controller的ActionResult

    示例代码 public ActionResult TypeOfForName() { Type typeinfo = typeof(CustomerClassController); //typeof ...

  2. html5-entities.js消失问题

    今天用nuxt做项目时,启动npm run dev,项目正常启动, 可过一会儿再试图启动时却报错: * ./libhtml5-entities.js in ./~/html-entities/inde ...

  3. Python安装setuptools时报Compression requires the (missing) zlib

    装机员为您提供Python安装setuptools时报Compression requires the (missing) zlib的文章咨询供您阅读,如何使用Python安装setuptools时报 ...

  4. 多版本python的使用

    装任一版本的virtualenv都可以 在创建virtualenv时只需指定python的安装位置就可使用该版本的python virtualenv --python=D:\install\pytho ...

  5. 【BZOJ1854】游戏[SCOI2009](神奇贪心+并查集)

    这道题和今年GDKOI的Day2T2很像(然而gdkoi的题用网络流可以A,这道题只能拿30). 网址:http://www.lydsy.com/JudgeOnline/problem.php?id= ...

  6. Datax官方笔记总结

    # DataX DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL.SQL Server.Oracle.PostgreSQL.HDFS.Hive.HBase.OTS. ...

  7. 使用Jenkins进行持续集成

    首先,我们从Jenkins官方网站https://jenkins.io/下载最新的war包.虽然Jenkins提供了Windows.Linux.OS X等各种安装程序,但是,这些安装程序都没有war包 ...

  8. cplusplus.com

    1/ http://www.cplusplus.com/reference/map/multimap/find/ 2. C

  9. java JDBC与MySQL 关于日间与日期

    //MySQL Date类型 -> java.sql.Date java.sql.Date d = new java.sql.Date(Calendar.getInstance().getTim ...

  10. IDEA提交Git时忽略文件【ignore文件备份】

    IntellJ IDEA设置ignore文件忽略,需: 第一步:下载idea的ignore插件,链接:https://pan.baidu.com/s/14_cfq56g1s7Lc6LdiolvWA 密 ...