AngularJS中的$watch(),$digest()和$apply()区分


Posted in Javascript onApril 04, 2016

AngularJS $scope里面的$watch(),$digest()和$apply()是AngularJS的核心函数,学习AngularJS必须理解这几个函数。

在绑定$scope中的变量到view的时候,AngularJS自动在内部创建一个"Watch"。"Watch"用于监听AngularJS scope中变量的改变。可以通过调用$scope.$watch()这个方法来创建"Watch"。

$scope.$digest()函数会循环访问所有的watches,并检测其所监听的$scope中的变量是否改变。如果变量发生改变,会调用该变量对应的监听函数。监听函数可以实现很多操作,比如让html里面的text文本显示最新的变量值。可见,$scope.$digest是可以触发数据绑定更新的。

大部分情况下,AngualrJS会自动调用$scope.$watch()和$scope.$digest()函数,但是在某些情况下,我们需要手动调用他们,因此,有必要了解他们是怎么工作的。

$scope.$apply()这个函数会先执行一些代码,之后在调用$scope.$digest()。所有的watches会被检测一次,相应的监听函数也会被执行。$scope.$apply()在AngularJS与其它javascript代码集成时是很有用的。

接下来我们具体的讲解下$watch(), $digest() 和 $apply()。

$watch()
$watch(watchExpression, listener, [objectEquality])

watchExpression:监听对象,可以是string或者function(scope){}

listener:监听对象发生改变时执行的回调函数function(newVal,oldVal,scope){}

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

$digest()
检测当前scope以及子scope中所有的watches,因为监听函数会在执行过程中修改model(scope中的变量),$digest()会一直被调用直到model没有再变。当调用超过10次时,$digest()会抛出一个异常"Maximum iteration limit exceeded',以此来防止程序进入一个死循环。

$apply()
$apply([exp])

exp:string或者function(scope){}

$apply()生命周期伪代码示意图如下

function $apply(expr) {
 try {
  return $eval(expr);
 } catch (e) {
  $exceptionHandler(e);
 } finally {
  $root.$digest();
 }
}

Example
下面我们通过一个例子来说明$watch,$digest和$apply。

<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController", function($scope) {
  $scope.data = { time : new Date() };
  $scope.updateTime = function() {
    $scope.data.time = new Date();
  }
   
  document.getElementById("updateTimeButton")
      .addEventListener('click', function() {
    console.log("update time clicked");
    $scope.data.time = new Date();
  });
});
</script>
<body ng-app="myapp">
<div ng-controller="myController">
  {{data.time}}
 
  <br/>
  <button ng-click="updateTime()">update time - ng-click</button>
  <button id="updateTimeButton" >update time</button>
</div>
</body>

这段代码会绑定$scope.data.time到HTML中显示出来,同时这个绑定会自动创建一个watch来监听$scope.date.time的变化。此外,这里还有2个按钮,第一个按钮是通过ng-click Directive来调用$scope.updateTime方法,之后AngularJS会自动执行$scope.$digest()使最新的时间显示到HTML中。第二个按钮是通过javascript代码添加一个点击事件,以此来更新HTML中的时间。但是第二个按钮是不能工作的,它的解决办法是在点击事件的最后手动的去调用$scope.$digest()方法,如下:

document.getElementById("updateTimeButton")
    .addEventListener('click', function() {
  console.log("update time clicked");
  $scope.data.time = new Date();
  $scope.$digest();
});

另外一个解决办法是调用$scope.$apply(),如下:

document.getElementById("updateTimeButton")
    .addEventListener('click', function() {
  $scope.$apply(function(){
      console.log("update time clicked");
      $scope.data.time = new Date();
    }
  );
});

以上就是本文的全部内容,希望对大家的学习有所帮助。

Javascript 相关文章推荐
jQuery教程 $()包装函数来实现数组元素分页效果
Aug 13 Javascript
js获取时间(本周、本季度、本月..)
Nov 22 Javascript
js用闭包遍历树状数组的方法
Mar 19 Javascript
JavaScript控制按钮可用或不可用的方法
Apr 03 Javascript
jquery实现向下滑出的二级导航下滑菜单效果
Aug 25 Javascript
JavaScript判断表单为空及获取焦点的方法
Feb 12 Javascript
详解用原生JavaScript实现jQuery的某些简单功能
Dec 19 Javascript
Bootstrap下拉菜单更改为悬停(hover)触发的方法
May 24 Javascript
JavaScript 中定义函数用 var foo = function () {} 和 function foo()区别介绍
Mar 01 Javascript
浅谈手写node可读流之流动模式
Jun 01 Javascript
微信小程序使用wxParse解析html的方法教程
Jul 06 Javascript
vue-cli4.x创建企业级项目的方法步骤
Jun 18 Javascript
Angular 根据 service 的状态更新 directive
Apr 03 #Javascript
jQuery中的Deferred和promise 的区别
Apr 03 #Javascript
再次谈论React.js实现原生js拖拽效果引起的一系列问题
Apr 03 #Javascript
jQuery qrcode生成二维码的方法
Apr 03 #Javascript
Node.js 应用跑得更快 10 个技巧
Apr 03 #Javascript
AngularJs 60分钟入门基础教程
Apr 03 #Javascript
深入浅析JSON.parse()、JSON.stringify()和eval()的作用详解
Apr 03 #Javascript
You might like
乱谈我对耳机、音箱的感受
2021/03/02 无线电
php,不用COM,生成excel文件
2006/10/09 PHP
PHP中查询SQL Server或Sybase时TEXT字段被截断的解决方法
2009/03/10 PHP
Trying to clone an uncloneable object of class Imagic的解决方法
2012/01/11 PHP
关于php中一些字符串总结
2016/05/05 PHP
PHP下载大文件失败并限制下载速度的实例代码
2019/05/10 PHP
Stop SQL Server
2007/06/21 Javascript
ExtJS 2.0实用简明教程 之ExtJS版的Hello
2009/04/29 Javascript
Visual Studio中的jQuery智能提示设置方法
2010/03/27 Javascript
JavaScript面向对象设计二 构造函数模式
2011/12/20 Javascript
javascript的parseFloat()方法精度问题探讨
2013/11/26 Javascript
jquery制作select列表双向选择示例代码
2014/09/02 Javascript
jQuery源码解读之removeClass()方法分析
2015/02/20 Javascript
Javascript 引擎工作机制详解
2016/11/30 Javascript
JS基于onclick事件实现单个按钮的编辑与保存功能示例
2017/02/13 Javascript
详解angular应用容器化部署
2018/08/14 Javascript
js中Generator函数的深入讲解
2019/04/07 Javascript
微信小程序上传多图到服务器并获取返回的路径
2019/05/05 Javascript
微信小程序自定义菜单切换栏tabbar组件代码实例
2019/12/30 Javascript
python脚本替换指定行实现步骤
2017/07/11 Python
Python Numpy 数组的初始化和基本操作
2018/03/13 Python
Python调用百度根据经纬度查询地址的示例代码
2019/07/07 Python
Pytorch 数据加载与数据预处理方式
2019/12/31 Python
Python Selenium截图功能实现代码
2020/04/26 Python
一款基于css3麻将筛子3D翻转特效的实例教程
2014/12/31 HTML / CSS
一些网络技术方面的面试题
2014/05/01 面试题
企业厂长岗位职责
2013/12/17 职场文书
医院检讨书范文
2014/02/01 职场文书
道路建设实施方案
2014/03/18 职场文书
俞敏洪励志演讲稿
2014/04/29 职场文书
学雷锋志愿者活动总结
2014/06/27 职场文书
部门2014年度工作总结
2014/11/12 职场文书
鸦片战争观后感
2015/06/09 职场文书
fastdfs+nginx集群搭建的实现
2021/03/31 Servers
Redis5之后版本的高可用集群搭建的实现
2021/04/27 Redis
一条 SQL 语句执行过程
2022/03/17 MySQL