全面解析Angular中$Apply()及$Digest()的区别(2)

/* What happens without an $apply() */ angular.module(‘myApp',[]).controller(‘MessageController', function($scope) { $scope.getMessage = function() { setTimeout(function() { $scope.message = ‘Fetched after 3 seconds'; console.log(‘message:'+$scope.message); }, 2000); } $scope.getMessage(); });

通过运行这个例子,你会看到过了两秒钟之后,控制台确实会显示出已经更新的model,然而,view并没有更新。原因也许你已经知道了,就是我们忘了调用$apply()方法。因此,我们需要修改getMessage(),如下所示:

/* What happens with $apply */ angular.module(‘myApp',[]).controller(‘MessageController', function($scope) { $scope.getMessage = function() { setTimeout(function() { $scope.$apply(function() { //wrapped this within $apply $scope.message = ‘Fetched after 3 seconds'; console.log(‘message:' + $scope.message); }); }, 2000); } $scope.getMessage(); });

如果你运行了上面的例子,你会看到view在两秒钟之后也会更新。唯一的变化是我们的代码现在被wrapped到了$scope.$apply()中,它会自动触发$rootScope.$digest(),从而让watchers被触发用以更新view。

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

而且,注意在以上的代码中你也可以在修改了model之后手动调用没有参数的$apply(),就像下面这样:

$scope.getMessage = function() { setTimeout(function() { $scope.message = ‘Fetched after two seconds'; console.log(‘message:' + $scope.message); $scope.$apply(); //this triggers a $digest }, 2000); };

以上的代码使用了$apply()的第二种形式,也就是没有参数的形式。需要记住的是你总是应该使用接受一个function作为参数的$apply()方法。这是因为当你传入一个function到$apply()中的时候,这个function会被包装到一个try…catch块中,所以一旦有异常发生,该异常会被$exceptionHandler service处理。

使用 $apply()的情况如下:

•通常可以依赖于Angular提供的可用于视图中的任意指令来调用 $apply() 。所有 ng-[event]指令(比如 ng-click 、 ng-keypress )都会调用 $apply() 。

•此外还可以依赖于一系列Angular内置的服务来调用 $digest() 。比如 $http 服务会在XHR请求完成并触发更新返回值(promise)之后调用 $apply() 。

•无论何时我们手动处理事件,使用第三方框架(比如jQuery、Facebook API) ,或者调用setTimeout() ,都可以使用 $apply() 函数让Angular返回 $digest 循环。

调用setTimeout():

<!DOCTYPE html> <html ng-app="myApp"> <head> <title>$scope.$apply()用法</title> <meta charset="utf-8"> <script src="https://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <body> <div ng-controller="mytext"> <div>{{text}}</div> <input type="button" value="jquery-event"></input> </div> </body> </html> <script type="text/javascript"> var myModule = angular.module('myApp', []); myModule.controller("mytext",function($scope){ $scope.text = "place"; setTimeout(function(){ $scope.text = "value setted after time out"; $scope.$apply();//必需手动进行脏值检测,否则数据无法刷新到界面 },1000); }); </script>

使用第三方框架(比如jQuery、Facebook API):

<!DOCTYPE html> <html ng-app="myApp"> <head> <title>$scope.$apply()用法</title> <meta charset="utf-8"> <script src="https://cdn.jsdelivr.net/jquery/3.1.0/jquery.min.js"></script> <script src="https://apps.bdimg.com/libs/angular.js/1.4.6/angular.min.js"></script> </head> <body> <div ng-controller="mytext"> <div>{{text}}</div> <input type="button" value="jquery-event"></input> </div> </body> </html> <script type="text/javascript"> var myModule = angular.module('myApp', []); myModule.controller("mytext",function($scope){ $scope.text = "place"; }); $(function(){ $("#btn").click(function(){ var $scope = $("#btn").scope(); $scope.text = "value setted in jquery"; $scope.$apply(); }); }) </script>

1.3、$digest循环会运行多少次?

当一个$digest循环运行时,watchers会被执行来检查scope中的models是否发生了变化。如果发生了变化,那么相应的listener函数就会被执行。这涉及到一个重要的问题。如果listener函数本身会修改一个scope model呢?AngularJS会怎么处理这种情况?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzxjjy.html