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 相关文章推荐
Packer 3.0 JS压缩及混淆工具 下载
May 03 Javascript
基于jQuery实现下拉收缩(展开与折叠)特效
Dec 25 Javascript
JS 去除Array中的null值示例代码
Nov 20 Javascript
详解JavaScript中的异常处理方法
Jun 16 Javascript
谈谈Jquery中的children find 的区别有哪些
Oct 19 Javascript
浅谈JQ中mouseover和mouseenter的区别
Sep 13 Javascript
AngularJS2中一种button切换效果的实现方法(二)
Mar 27 Javascript
MUI 上拉刷新/下拉加载功能实例代码
Apr 13 Javascript
解决layer弹出层的内容页点击按钮跳转到新的页面问题
Sep 14 Javascript
JavaScript变量Dom对象的所有属性
Apr 30 Javascript
Element DateTimePicker日期时间选择器的使用示例
Jul 27 Javascript
vue项目接口管理,所有接口都在apis文件夹中统一管理操作
Aug 13 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
php环境配置 php5 mysql5 apache2 phpmyadmin安装与配置
2006/11/17 PHP
Joomla下利用configuration.php存储简单数据
2010/05/19 PHP
如何判断php数组的维度
2013/06/10 PHP
php教程之魔术方法的使用示例(php魔术函数)
2014/02/12 PHP
ThinkPHP实现将本地文件打包成zip下载
2014/06/26 PHP
PHP中对各种加密算法、Hash算法的速度测试对比代码
2014/07/08 PHP
ThinkPHP框架设计及扩展详解
2014/11/25 PHP
php版微信公众平台回复中文出现乱码问题的解决方法
2016/09/22 PHP
PHP实现登录注册之BootStrap表单功能
2017/09/03 PHP
thinkPHP框架中layer.js的封装与使用方法示例
2019/01/18 PHP
javascript 检测浏览器类型和版本的代码
2009/09/15 Javascript
jQuery实现首页顶部可伸缩广告特效代码
2015/04/15 Javascript
JS实现状态栏跑马灯文字效果代码
2015/10/24 Javascript
ionic由于使用了header和subheader导致被遮挡的问题的两种解决方法
2016/09/22 Javascript
详解如何在NodeJS项目中优雅的使用ES6
2017/04/22 NodeJs
Angular.js指令学习中一些重要属性的用法教程
2017/05/24 Javascript
详解vue.js+UEditor集成 [前后端分离项目]
2017/07/07 Javascript
微信小程序左滑动显示菜单功能的实现
2018/06/14 Javascript
Vue filter格式化时间戳时间成标准日期格式的方法
2018/09/16 Javascript
微信小程序日历组件使用方法详解
2018/12/29 Javascript
微信小程序实现九宫格抽奖
2020/04/15 Javascript
Vue通过Blob对象实现导出Excel功能示例代码
2020/07/31 Javascript
解决ant-design-vue中menu菜单无法默认展开的问题
2020/10/31 Javascript
Python入门教程之if语句的用法
2015/05/14 Python
Python中http请求方法库汇总
2016/01/06 Python
Python3实现发送QQ邮件功能(html)
2017/12/15 Python
基于MSELoss()与CrossEntropyLoss()的区别详解
2020/01/02 Python
Django分组聚合查询实例分享
2020/04/29 Python
Keras 实现加载预训练模型并冻结网络的层
2020/06/15 Python
法国二手手袋、手表和奢侈珠宝购物网站:Collector Square
2018/07/05 全球购物
《小猫刮胡子》教学反思
2014/02/21 职场文书
合同纠纷调解书
2015/05/20 职场文书
导游词之无锡东林书院
2019/12/11 职场文书
关于CentOS 8 搭建MongoDB4.4分片集群的问题
2021/10/24 MongoDB
Flutter集成高德地图并添加自定义Maker的实践
2022/04/07 Java/Android
python如何查找列表中元素的位置
2022/05/30 Python