AngularJs学习笔记(3)--$scope中的$apply和$digest方法

10 篇文章 0 订阅


http://xlows.blog.51cto.com/5380484/1425325


首先,我们利用angular在页面上输出当前的时间,这个并不难,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
< html >
< head >
     < meta  charset = "utf-8" >
</ head >
< body >
     < div  ng-app = "" >
 
         < div  ng-controller = "firstController" >
             {{date}}
         </ div >
     </ div >
 
 
     < script  type = "text/javascript"  src = "app/index.js" ></ script >
< script  type = "text/javascript"  src = "../../vendor/angular/angularjs.js" ></ script >
</ body >
</ html >
1
2
3
4
5
var  firstController =  function ($scope){
 
     $scope.date =  new  Date();
 
}

此时页面会输出当前时间。

wKioL1OZHWrDFugiAAAXdOUq9RA634.jpg

那么,现在有一个需求,要求时间每秒中更新一次。

我们把js代码改成如下:

1
2
3
4
5
6
7
8
9
10
var  firstController =  function ($scope){
 
     $scope.date =  new  Date();
 
     setInterval( function (){
 
         $scope.date =  new  Date();
 
     },1000)
}

在运行,发现页面并没有每秒刷新一次。那么在Model中变的时候,如何通知页面变化呢?


(1)什么是scope

scope是一个指向应用model的object,也是表达式的执行上下文,它被放置于一个类似应用的DOM结构的层次结构中。

(2)angular是怎么知道变量发生了改变

①要知道一个变量变了,方法不外乎两种

  1. 能通过固定的接口才能改变变量的值,比如说只能通过set()设置变量的值,set被调用时比较一下就知道了。这种方法的缺点是写法繁琐。

  2. 脏检查,将原对象复制一份快照,在某个时间,比较现在对象与快照的值,如果不一样就表明发生变化,这个策略要保留两份变量,而且要遍历对象,比较每个属性,这样会有一定性能问题

②angular的策略

angular的实现是使用脏检查

  1. 不会脏检查所有的对象,当对象被绑定到html中,这个对象添加为检查对象(watcher)。

  2. 不会脏检查所有的属性,同样当属性被绑定后,这个属性会被列为检查的属性。

  3. 在angular程序初始化时,会将绑定的对象的属性添加为监听对象(watcher),也就是说一个对象绑定了N个属性,就会添加N个watcher。

③什么时候去脏检查

angular所有系统的方法中都会触发比较事件,比如:

controller初始化的时候,所有以ng-开头的时间执行后,都会触发脏检查。

因此,可以想到,在第一次加载页面时候,controller初始化的时候,会检查其中的date,进行第一次赋值。

而后setInterval每秒触发一次,此时date虽然变了,但是并没有触发脏检查,因此不会触发页面上的改变。

(3)手动触发脏检查

$apply仅仅只是进入angular context,然后通过$digest方法去触发脏检查

$apply如果不给参数的话,会检查该$scope里的所有监听的属性,推荐给上参数。


通过上面的说明,我们可以js代码改成如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var  firstController =  function ($scope){
 
     $scope.date =  new  Date();
 
     setInterval( function (){
         $scope.$apply( function (){
             $scope.date =  new  Date();
             //....会去触发脏检查
         })
     },1000)
 
 
     // 触发一次脏检查
}

此时,页面每个1秒会更新一次时间。


看一下$apply的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   $apply:  function (expr) {
               try  {
                  beginPhase( '$apply' );
                  return  this .$eval(expr);
               catch  (e) {
                  $exceptionHandler(e);
               } finally {
                  clearPhase();
                  try  {
                    $rootScope.$digest();
                  catch  (e) {
                    $exceptionHandler(e);
                    throw  e;
                  }
               }
    }

可以看到,$apply方法首先会通过$eval来解析里面的表达式,如果表达式有错会抛出错误,如果没有错误才会触发$digest方法。


(4)关于$digest()

其控制器所属的scope和其所有子scope的脏检查,脏检查又会触发$watch(),整个angular双向绑定机制就活了过来

这里不建议直接调用$digest(),而应该使用$apply,$apply其实不能把信直接送给$digest,之间还有$eval门卫把关,如果$apply带的表达式不合法,$eval会把错误交给$exceptionHandler,合法才会触发$digest,所有更安全。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
$scope.$$phase是AngularJS的一个属性,用于检测当前是否处于脏值检测的过程。\[1\]在AngularJS,脏值检测是用来检测数据模型的变化并更新视图的过程。当数据模型发生变化时,AngularJS会自动触发脏值检测,然后更新相应的视图。 在引用\[1\]和引用\[2\],$scope.$$phase被用来判断当前是否处于脏值检测的过程。如果不处于脏值检测的过程,就可以调用$scope.$apply()方法来手动触发脏值检测,从而更新视图。而如果已经处于脏值检测的过程,就不需要再调用$scope.$apply()方法了,以避免出现错误。 引用\[3\]提到了可能会遇到的错误:Error: \[$rootScope:inprog\] $digest already in progress。这个错误表示在脏值检测的过程又尝试触发了脏值检测,导致了循环调用的错误。为了避免这个错误,可以使用条件判断来判断是否需要调用$scope.$apply()方法,就像引用\[2\]的代码所示。 综上所述,$scope.$$phase是用来判断当前是否处于脏值检测的过程的属性。根据不同的情况,可以使用$scope.$apply()方法来手动触发脏值检测,以更新视图。但是需要注意避免在脏值检测的过程再次触发脏值检测,以避免出现循环调用的错误。 #### 引用[.reference_title] - *1* [angular 手动刷新值 $scope.$apply()](https://blog.csdn.net/lybwwp/article/details/108348059)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [angulr 报错:$digest already in progress](https://blog.csdn.net/Nonsense_man/article/details/91422403)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值