最近项目上使用了比较多的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 (===).

angularJS之$watch、$digest和$apply方法的更多相关文章

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

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

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

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

  3. AngularJS中的digest循环$apply

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

  4. angularjs $scope.$apply 方法详解

    myApp.controller('firstController',function($scope,$interval){ $scope.date = new Date(); setInterval ...

  5. angularJS--apply() 、digest()和watch()方法

    外文网址:http://www.sitepoint.com/understanding-angulars-apply-digest/ $apply()和$digest()在AngularJS中是两个核 ...

  6. angularJS之$apply()方法

    这几天,根据buddy指定的任务,要分享一点angular JS的东西.对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的阻力还真是不少.不 ...

  7. angularJS中$apply()方法详解

    这篇文章主要介绍了angularJS中$apply()方法详解,需要的朋友可以参考下   对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的 ...

  8. 【学】AngularJS日记(3)- $apply(), run()方法

    $scope.$apply()方法可以强制$apply()里运行的函数所改变的model里的数据直接反应到view里,因为在angular的环境中,有时会用到原生js或者jquery的时候,这些行为有 ...

  9. angularJS $scope的$apply方法实现model刷新

    控制器内,$scope有个$apply方法,可以代码更改model并同步更新页面.通常,控制器内的方法执行完毕后仅会自动刷新一次页面展示,使用$apply方法即可在想刷新页面时就刷新.如本例,这个方法 ...

随机推荐

  1. extjs实现多国语音切换

    http://kuyur.info/blog/archives/2490 http://blog.chinaunix.net/uid-28661623-id-3779637.html http://b ...

  2. iOS7 隐藏状态栏 hide statusBar

    1.调用 [self setNeedsStatusBarAppearanceUpdate]; 2.重载以下函数 - (BOOL)prefersStatusBarHidden{ return _hide ...

  3. java数据结构和算法------冒泡排序

    package iYou.neugle.sort; public class Bubble_sort { public static void BubbleSort(double[] array) { ...

  4. Java类初始化顺序问题

    main -> (静态变量.静态代码块) ->main函数体 -> (类变量.初始化块.实例化引用的类) -> 构造函数 初始化块与实例化引用的类 的调用顺序 按程序的编写上下 ...

  5. 网络笔记02数据解析 -1-JSON解析

    1.JSON解析 1.JSON介绍 JSON是最网络传输数据最为广泛的数据格式,没有之一,出身草根,是Javascript的子集,专门负责描述数据格式.Javascript是网页开发的一种脚本语言,和 ...

  6. Java实现文件压缩与解压[zip格式,gzip格式]

    Java实现ZIP的解压与压缩功能基本都是使用了Java的多肽和递归技术,可以对单个文件和任意级联文件夹进行压缩和解压,对于一些初学者来说是个很不错的实例. zip扮演着归档和压缩两个角色:gzip并 ...

  7. 用PHP向数据库中添加数据

    显示页面(用户可见) <body><form action="chuli.php" method="post">  //将该页面接收的数 ...

  8. 【BZOJ】【1069】【SCOI2007】最大土地面积

    计算几何/旋转卡壳 从已知点中选出四个使得选出的四边形面积最大,很明显我们应该在凸包上搞. 我一开始的思路是:枚举 i ,找到 i 的对锺点cur1,这两个点将凸包分成了两半,我们在左半中枚举一个 j ...

  9. 项目分析(PLUG)

    plug过程 .INIT_PLUG #define INIT_PLUG Plug::InitPlug g_InitPlug(true); //共享内存数据结构 struct PlugShareMemo ...

  10. 管理员必须掌握的八个cmd命令

    一.ping   它是用来检查网络是否通畅或者网络连接速度的命令.作为一个生活在网络上的管理员或者黑客来说,ping命令是第一个必须掌握的DOS命令,它所利用的原理是这样的:网络上的机器都有唯一确定的 ...