AngularJS报错$apply already in progress的解决方法分析
GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!
【 如果你想靠AI翻身,你先需要一个靠谱的工具! 】
本文实例分析了AngularJS报错$apply already in progress的解决方法。分享给大家供大家参考,具体如下:
如果我们使用了AngularJS中的$scope.$apply()或者$scope.$digest(),我们很可能会遇到类似下面的错误,虽然这个错误没有太大影响,但是在日志中看起来还是很不爽的,日志中记录的异常或者错误,就应该是需要关注和解决的问题,否则就没有必要出现在日志中了。
1 2 3 4 5 6 7 8 9 10 11 12 | Error: [$rootScope:inprog] $apply already in progress http: //errors .angularjs.org /1 .3.13/$rootScope /inprog ?p0=%24apply at angular.js:63 at beginPhase (angular.js:14755) at Scope.$apply (angular.js:14499) at new <anonymous> (1%20-%20%E5%89%AF%E6%9C%AC.html:10) at Object.invoke (angular.js:4185) at extend.instance (angular.js:8454) at angular.js:7700 at forEach (angular.js:331) at nodeLinkFn (angular.js:7699) at compositeLinkFn (angular.js:7078) |
下面这段代码就会报上面这个错误:
1 2 3 4 5 6 | var myModule = angular.module( 'myModule' , []); myModule.controller( "ctrl_1" , function ($scope){ $scope.value = "aty" ; $scope.$apply(); //$scope.$digest(); }); |
这个错误其实很好理解:angularJS框架本身已经在做脏数据检测了,我们没有必要再手动调用$apply或者$digest。这里自然而然出现了一个疑问:什么时候需要我们手动调用$apply或者$digest,什么时候不需要呢?这是个好问题,我现在也不知道,目前我只能列出自己在项目中遇到的2种需要手动调用$apply的情况。
情况1:controller中如果有异步操作,比如ajax回调,timeout延时等。可以这么理解:由于异步(延迟)的存在,当开始执行回调函数的时候,angularJS自身controller中的脏值检测已经结束,无法检测到回调函数导致数据的变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | <html> <head> <script src= "jquery-1.11.1.min.js" ></script> <script src= "angular.js" ></script> <script> var myModule = angular.module( 'myModule' , []); myModule.controller( "ctrl_1" , function ($scope){ $scope.text = "place" ; setTimeout( function (){ $scope.text = "value setted after time out" ; $scope.$apply(); //必需手动进行脏值检测,否则数据无法刷新到界面 },1000); }); $( function (){ angular.bootstrap($( "#div1" )[0], [ "myModule" ]); }) </script> </head> <body> <div id= "div1" ng-controller= "ctrl_1" > <div>{{text}}</div> <input id= "btn" type= "button" value= "jquery-event" ></input> </div> </body> </html> |
这段代码如果没有调用$scope.$apply()的话,数据是不会刷新到界面上的。
情况2:在jQuery代码中修改$scope中的数据。这种情况是在angular框架之外操作$scope中的数据,angular不能检测到数据变化是正常的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <html> <head> <script src= "jquery-1.11.1.min.js" ></script> <script src= "angular.js" ></script> <script> var myModule = angular.module( 'myModule' , []); myModule.controller( "ctrl_1" , function ($scope){ $scope.text = "place" ; }); $( function (){ angular.bootstrap($( "#div1" )[0], [ "myModule" ]); $( "#btn" ).click( function (){ var $scope = $( "#btn" ).scope(); $scope.text = "value setted in jquery" ; $scope.$apply(); }); }) </script> </head> <body> <div id= "div1" ng-controller= "ctrl_1" > <div>{{text}}</div> <input id= "btn" type= "button" value= "jquery-event" ></input> </div> </body> </html> |
在JQuery的事件处理函数中,我们能够通过dom拿到其关联的$scope对象,进而修改$scope中的数据。这种情况下,也必需要手动调用$scope.$apply()。
也就是说我们必须要清楚哪儿些情况需要手动$apply,哪儿些情况不需要手动$apply,这看起来很简单,实际上并不是这样的。看一段我们项目中的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | var myModule = angular.module( 'myModule' , []); myModule.controller( "ctrl_1" , function ($scope){ $scope.listItems = []; $scope.loadListFromService = function (){ Spl.MessageProcessor.loadData({ serviceId : "url" , data : {}, success : function (json) { $scope.listItems = json.results; // 要不要$scope.$apply()? }, error: function () { console.error( "invoke service[" +optionsJson.serviceId+ "] error." ); } }); } $scope.loadListFromService(); }); |
loadData()这个函数很像ajax回调,确实是这样的,这个API不过是做了一点封装,大致代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function loadData(options) { // 从本地缓存中读取,很快 var dataInCache = U.loadDataFromCache(options.serviceId); if (dataInCache) { options.success(dataInCache); } else { //异步ajax U.readDataFromServer(options.serviceId, options.data, function (response){ options.success(response); }); } } |
由于缓存的影响,$scope.loadListFromService()变得不再那么可控,如果本地已经有缓存了,那直接读取缓存是很快的,这个时候不需要手动$apply;如果是第一次,本地没有缓存,那么就变成了情况1,我们需要手动$apply。显然调用loadData()函数的地方,不需要也不应该关注到底有没有缓存的存在,这个时候判断需要不要手动$apply就没有那么容易的。简单粗暴的方式,不管怎么样都手动调用下$scope.$apply(),这样功能不会有问题,但是日志中就不可避免要出现文中开头提到的错误。
angular中的$scope中提供了一个$$phase变量,如果这个变量的值是"$digest" 或者"$apply",就代表angular自身已经在做脏值检测了,不需要我们再去调用$apply或者$digest;否则的话就需要我们手动调用$apply或者$digest了。利用这个属性,我们就可以方便解决上面的错误了,判断一下呗。下面是一个工具函数,好理解吧。
1 2 3 4 5 | function safeApply(scope, fn) { (scope. phase||scope.$root. phase) ? fn() : scope.$apply(fn); } |
最后提一下,$digest、$apply、$$phase这些属性或者方法其实都是$scope中的私有的,最好不要使用。如果你用到了这些方法,基本可以断言你的代码存在问题,没有按照angular的方式来组织代码。比如情况1中的setTimeout,完全可以用angular中的$timeout代替,这才是推荐的方式,而不是通过$apply来补救。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <html> <head> <script src= "jquery-1.11.1.min.js" ></script> <script src= "angular.js" ></script> <script> var myModule = angular.module( 'myModule' , []); myModule.controller( "ctrl_1" , function ($scope, $timeout){ $scope.text = "place" ; $timeout( function (){ $scope.text = "value setted after time out" ; },1000); }); $( function (){ angular.bootstrap($( "#div1" )[0], [ "myModule" ]); }) </script> </head> <body> <div id= "div1" ng-controller= "ctrl_1" > <div>{{text}}</div> <input id= "btn" type= "button" value= "jquery-event" ></input> </div> </body> </html> |
所以解决“$apply already in progress”最好的方式,就是不要使用$scope.$apply()或者$scope.$digest()。
更多关于AngularJS相关内容感兴趣的读者可查看本站专题:《AngularJS入门与进阶教程》及《AngularJS MVC架构总结》
希望本文所述对大家AngularJS程序设计有所帮助。
- angularJS中$apply()方法详解
- 浅谈angular.js中实现双向绑定的方法$watch $digest $apply
- AngularJS中的$watch(),$digest()和$apply()区分
- 全面解析Angular中$Apply()及$Digest()的区别
- AngularJS中$apply方法和$watch方法用法总结
- Angular项目中$scope.$apply()方法的使用详解
- angularjs 中$apply,$digest,$watch详解
- Angular.js中$apply()和$digest()的深入理解
- AngularJS双向数据绑定原理之$watch、$apply和$digest的应用
- Angularjs中的$apply及优化使用详解
微信公众号搜索 “ 脚本之家 ” ,选择关注
程序猿的那些事、送书等活动等着你
相关文章
Angular 2父子组件数据传递之@ViewChild获取子组件详解
这篇文章主要给大家介绍了关于Angular 2父子组件数据传递之@ViewChild获取子组件的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定参考学习价值,需要的朋友们下面来一起看看吧。2017-07-07Angular.JS利用ng-disabled属性和ng-model实现禁用button效果
这篇文章主要介绍了Angular.JS利用ng-disabled属性和ng-model实现禁用button效果的相关资料,文中给出了详细的示例代码,相信对大家具有一定的参考价值,需要的朋友们下面来一起看看吧。2017-04-04将angular.js项目整合到.net mvc中的方法详解
这篇文章主要给大家介绍了将angular.js项目整合到.net mvc中的相关资料,文中通过示例代码将实现的过程介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面跟着小编来一起看看吧。2017-06-06Angular中使用$watch监听object属性值的变化(详解)
下面小编就为大家带来一篇Angular中使用$watch监听object属性值的变化(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧2017-04-04
最新评论