明亮Angular中的$apply()以及$digest()

 

  1. <body ng-app=”myApp”>  
  2.   <div ng-controller=”MessageController”>  
  3.     Delayed Message: {{message}}  
  4.   </div>    
  5. </body>  

 

[javascript] view
plain
 copy

 

 

  1. $scope.getMessage = function() {  
  2.   setTimeout(function() {  
  3.     $scope.message = ‘Fetched after two seconds’;  
  4.     console.log(‘message:’ + $scope.message);  
  5.     $scope.$apply(); //this triggers a $digest  
  6.   }, 2000);
  7. };  

AngularJS提供了一个不胜酷的性状叫做双向数据绑定(Two-way Data Binding),那本个性大大简化了笔者们的代码编写格局。数据绑定意味着当View中有此外数据发生了变动,那么那么些变化也会自行地申报到scope的多少上,也即意味着scope模型会活动地立异。类似地,当scope模型产生变化时,view中的数据也会更新到新型的值。那么AngularJS是怎么成功那或多或少的呢?当你写下表明式如{{
aModel }}时,AngularJS在幕后会为您在scope模型上安装2个watcher,它用来在数据发生变化的时候更新view。那里的watcher和您会在AngularJS中安装的watcher是同等的:

 

 

透过运转那几个例子,你汇合到过了两秒钟之后,调节台确实会突显出已经更新的model,但是,view并从未革新。原因大概你早已了然了,便是我们忘了调用$apply()方法。因而,大家需求修改getMessage(),如下所示:

 

[javascript] view
plain
 copy

[javascript] view
plain
 copy

 

答案是$digest循环不会只运转二次。在脚下的三回巡回甘休后,它会再施行一遍循环用来检查是还是不是有models产生了变动。那就是脏检查(Dirty Checking),它用来处理在listener函数被实践时大概引起的model变化。因而,$digest循环会持续运行直到model不再爆发变化,恐怕$digest循环的次数达到了十回。因而,尽大概地并非在listener函数中期维修改model。

Note: $scope.$apply()会活动地调用$rootScope.$digest()。$apply()方法有二种样式。第3种会接受2个function作为参数,施行该function并且触发一轮$digest循环。第三种会不收受任何参数,只是触发一轮$digest循环。大家立即会面到为啥第三种方式更加好。

笔者盼望那篇小说解释清楚了$apply和$digest。要求记住的最要紧的是AngularJS是不是能检验到您对此model的修改。假设它无法检查测试到,那么您就供给手动地调用$apply()。

  1. /* What happens with $apply */   
  2. angular.module(‘myApp’,[]).controller(‘MessageController’, function($scope) {  
  3.       
  4.       $scope.getMessage = function() {  
  5.         setTimeout(function() {  
  6.           $scope.$apply(function() {  
  7.             //wrapped this within $apply  
  8.             $scope.message = ‘Fetched after 3 seconds’;   
  9.             console.log(‘message:’ + $scope.message);  
  10.           });  
  11.         }, 2000);  
  12.       }  
  13.         
  14.       $scope.getMessage();  
  15.       
  16.     });  

 

盛传到$watch()中的第1个参数是七个回调函数,该函数在aModel的值发生变化的时候会被调用。当aModel发生变化的时候,那么些回调函数会被调用来更新view那点简单理解,不过,还设有二个很要紧的主题材料!AngularJS是怎么着知道怎么着时候要调用这一个回调函数呢?换句话说,AngularJS是怎么知晓aModel发生了改换,才调用了相应的回调函数呢?它会周期性的周转1个函数来检查scope模型中的数据是不是爆发了变化吧?好呢,那正是$digest循环的用武之地了。

要是AngularJS总是将大家的代码wrap到3个function中并传到$apply(),以此来初叶壹轮$digest循环,那么如曾几何时候才需求大家手动地调用$apply()方法呢?实际上,AngularJS对此有所格外显眼的渴求,正是它只担负对发生于AngularJS上下文环境中的改动会做出自动地响应(即,在$apply()方法中发出的对于models的变动)。AngularJS的built-in指令便是那般做的,所以任何的model改动都会被反映到view中。不过,若是您在AngularJS上下文之外的其他地点修改了model,那么您就需求经过手动调用$apply()来通知AngularJS。那就如告诉AngularJS,你改改了部分models,希望AngularJS帮您触发watchers来做出正确的响应。

[html] view
plain
 copy

 

 

 

若果你运维了下边包车型大巴事例,你会看出view在两分钟之后也会更新。唯壹的变动是大家的代码以往被wrapped到了$scope.$apply()中,它会活动触发$rootScope.$digest(),从而让watchers被触发用以更新view。

 

 

HTML:

 

 

 

  1. $scope.$watch(‘aModel’, function(newValue, oldValue) {  
  2.   //update the DOM with newValue  
  3. });  

 

 

今昔,假若你将ng-click指令关联到了贰个button上,并传播了多个function名到ng-click上。当该button被点击时,AngularJS会将此function包装到一个wrapping function中,然后传入到$scope.$apply()。因而,你的function会符合规律被试行,修改models(借使必要的话),此时1轮$digest循环也会被触发,用来担保view也会被更新。

初稿地址

Note: $digest循环最少也会运作一次,即便在listener函数中并从未改换任何model。正如下边钻探的那么,它会多运转二回来确定保证models没有变动。

 

[javascript] view
plain
 copy

探索$apply()和$digest()

$apply()和$digest()在AngularJS中是三个为主概念,但是有时它们又令人质疑。而为了打探AngularJS的工作办法,首先必要驾驭$apply()和$digest()是什么样行事的。这篇小说意在解释$apply()和$digest()是怎么样,以及在常常的编码中哪些使用它们。

 

$digest循环会运行多少次?

上述的代码应用了$apply()的第三种方式,也正是未有参数的情势。供给牢记的是您总是应该使用接受一个function作为参数的$apply()方法。那是因为当您传入一个function到$apply()中的时候,那些function会棉被服装进到一个try…catch块中,所以假诺有1贰分发生,该越发会被$exceptionHandler service处理。

在调用了$scope.$digest()后,$digest循环就起来了。如果你在八个ng-click指令对应的handler函数中改造了scope中的一条数据,此时AngularJS会自动地通过调用$digest()来触发1轮$digest循环。当$digest循环初步后,它会接触每种watcher。这一个watchers会检查scope中的当前model值是不是和上贰遍总括获得的model值分歧。假若分化,那么相应的回调函数会被实行。调用该函数的结果,便是view中的表明式内容(译注:诸如{{ aModel
}})会被更新。除了ng-click指令,还有壹些别样的built-in指令以及劳动来让您转移models(比如ng-model,$timeout等)和活动触发2遍$digest循环。

结语

当多少个$digest循环运转时,watchers会被实行来检查scope中的models是或不是发生了变动。若是产生了变通,那么相应的listener函数就会被施行。那关乎到二个至关心珍视要的标题。假使listener函数本身会修改2个scope model呢?AngularJS会怎么处理那种景况?

 

哪些时候手动调用$apply()方法?

 

 

 

  1. /* What happens without an $apply() */  
  2.       
  3.     angular.module(‘myApp’,[]).controller(‘MessageController’, function($scope) {  
  4.       
  5.       $scope.getMessage = function() {  
  6.         setTimeout(function() {  
  7.           $scope.message = ‘Fetched after 3 seconds’;  
  8.           console.log(‘message:’+$scope.message);  
  9.         }, 2000);  
  10.       }  
  11.         
  12.       $scope.getMessage();  
  13.       
  14.     });  

 

 

 

JavaScript:

比如说,如若您采纳了JavaScript中的setTimeout()来更新3个scope model,那么AngularJS就未有章程知道您转移了什么样。那种景观下,调用$apply()就是你的权力和义务了,通过调用它来触发一轮$digest循环。类似地,假设你有七个命令用来安装1个DOM事件listener并且在该listener中期维修改了有的models,那么你也要求通过手动调用$apply()来保证更动会被科学的展示到view中。

 

 

Note:顺便提一下,你应有使用$timeout service来代替setTimeout(),因为前者会帮你调用$apply(),让你不必要手动地调用它。

http://www.sitepoint.com/understanding-angulars-apply-digest/

 

 

在$digest循环中,watchers会被触发。当贰个watcher被触发时,AngularJS会检验scope模型,怎么样它产生了转换那么涉及到该watcher的回调函数就会被调用。那么,下二个难题正是$digest循环是在如哪一天候以各样措施初阶的?

让我们来看三个事例。插手你有三个页面,1旦该页面加载实现了,你期望在两分钟之后显得一条消息。你的贯彻只怕是上边这几个样子的:

 

 

 

还要,注意在以上的代码中您也得以在改造了model之后手动调用没有参数的$apply(),就如下边那样:

如今停止还不易!不过,有二个小意思。在上头的例子中,AngularJS并不直接调用$digest(),而是调用$scope.$apply(),后者会调用$rootScope.$digest()。由此,1轮$digest循环在$rootScope初步,随后会造访到全体的children scope中的watchers。

相关文章