国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
(二十) 理解和解決angularJS報錯$apply already in progress

如果我們使用了AngularJS中的$scope.$apply()或者$scope.$digest(),我們很可能會遇到類似下面的錯誤,雖然這個錯誤沒有太大影響,但是在日志中看起來還是很不爽的,日志中記錄的異?;蛘咤e誤,就應(yīng)該是需要關(guān)注和解決的問題,否則就沒有必要出現(xiàn)在日志中了。

[plain] view plain copy
  1. Error: [$rootScope:inprog] $apply already in progress  
  2. http://errors.angularjs.org/1.3.13/$rootScope/inprog?p0=%24apply  
  3.     at angular.js:63  
  4.     at beginPhase (angular.js:14755)  
  5.     at Scope.$apply (angular.js:14499)  
  6.     at new <anonymous> (1%20-%20%E5%89%AF%E6%9C%AC.html:10)  
  7.     at Object.invoke (angular.js:4185)  
  8.     at extend.instance (angular.js:8454)  
  9.     at angular.js:7700  
  10.     at forEach (angular.js:331)  
  11.     at nodeLinkFn (angular.js:7699)  
  12.     at compositeLinkFn (angular.js:7078)  
下面這段代碼就會報上面這個錯誤:
[javascript] view plain copy
  1. var myModule = angular.module('myModule', []);    
  2. myModule.controller("ctrl_1",function($scope){  
  3. $scope.value = "aty";  
  4. $scope.$apply();  
  5. //$scope.$digest();  
  6. });  

這個錯誤其實很好理解:angularJS框架本身已經(jīng)在做臟數(shù)據(jù)檢測了,我們沒有必要再手動調(diào)用$apply或者$digest。這里自然而然出現(xiàn)了一個疑問:什么時候需要我們手動調(diào)用$apply或者$digest,什么時候不需要呢?這是個好問題,我現(xiàn)在也不知道,目前我只能列出自己在項目中遇到的2種需要手動調(diào)用$apply的情況。


情況1:controller中如果有異步操作,比如ajax回調(diào),timeout延時等。可以這么理解:由于異步(延遲)的存在,當開始執(zhí)行回調(diào)函數(shù)的時候,angularJS自身controller中的臟值檢測已經(jīng)結(jié)束,無法檢測到回調(diào)函數(shù)導致數(shù)據(jù)的變化。

  1. <html>  
  2.   <head>  
  3.     <script src="jquery-1.11.1.min.js"></script>  
  4.     <script src="angular.js"></script>    
  5.     <script>  
  6.           
  7.         var myModule = angular.module('myModule', []);    
  8.         myModule.controller("ctrl_1",function($scope){  
  9.             $scope.text = "place";  
  10.               
  11.             setTimeout(function(){  
  12.                 $scope.text = "value setted after time out";  
  13.                 $scope.$apply();//必需手動進行臟值檢測,否則數(shù)據(jù)無法刷新到界面  
  14.             },1000);  
  15.           
  16.         });   
  17.           
  18.         $(function(){  
  19.             angular.bootstrap($("#div1")[0], ["myModule"]);   
  20.               
  21.         })  
  22.     </script>  
  23.   </head>  
  24.   <body>  
  25.     <div id="div1" ng-controller="ctrl_1">  
  26.         <div>{{text}}</div>  
  27.         <input id="btn" type="button" value="jquery-event"></input>       
  28.     </div>    
  29.   </body>  
  30. </html>  
  31.   
  32.       
  33.       
這段代碼如果沒有調(diào)用$scope.$apply()的話,數(shù)據(jù)是不會刷新到界面上的。


情況2:在jQuery代碼中修改$scope中的數(shù)據(jù)。這種情況是在angular框架之外操作$scope中的數(shù)據(jù),angular不能檢測到數(shù)據(jù)變化是正常的。

  1. <html>  
  2.   <head>  
  3.     <script src="jquery-1.11.1.min.js"></script>  
  4.     <script src="angular.js"></script>    
  5.     <script>  
  6.           
  7.         var myModule = angular.module('myModule', []);    
  8.         myModule.controller("ctrl_1",function($scope){  
  9.             $scope.text = "place";  
  10.         });   
  11.           
  12.         $(function(){  
  13.             angular.bootstrap($("#div1")[0], ["myModule"]);   
  14.   
  15.             $("#btn").click(function(){  
  16.                 var $scope = $("#btn").scope();  
  17.                 $scope.text = "value setted in jquery";  
  18.                 $scope.$apply();  
  19.             });           
  20.         })  
  21.     </script>  
  22.   </head>  
  23.   <body>  
  24.     <div id="div1" ng-controller="ctrl_1">  
  25.         <div>{{text}}</div>  
  26.         <input id="btn" type="button" value="jquery-event"></input>       
  27.     </div>    
  28.   </body>  
  29. </html>  
  30.   
  31.       
在JQuery的事件處理函數(shù)中,我們能夠通過dom拿到其關(guān)聯(lián)的$scope對象,進而修改$scope中的數(shù)據(jù)。這種情況下,也必需要手動調(diào)用$scope.$apply()。

也就是說我們必須要清楚哪兒些情況需要手動$apply,哪兒些情況不需要手動$apply,這看起來很簡單,實際上并不是這樣的??匆欢挝覀冺椖恐械拇a:

[javascript] view plain copy
  1. var myModule = angular.module('myModule', []);    
  2. myModule.controller("ctrl_1",function($scope){  
  3.     $scope.listItems = [];  
  4.       
  5.     $scope.loadListFromService = function(){  
  6.         Spl.MessageProcessor.loadData({  
  7.                     serviceId : "url",  
  8.                     data : {},  
  9.                     success : function(json) {  
  10.                         $scope.listItems = json.results;  
  11.             // 要不要$scope.$apply()?  
  12.                     },  
  13.                     error: function() {  
  14.                         console.error("invoke service["+optionsJson.serviceId+"] error.");  
  15.                     }  
  16.         });  
  17.       
  18.     }  
  19.       
  20.     $scope.loadListFromService();  
  21.       
  22. });  
loadData()這個函數(shù)很像ajax回調(diào),確實是這樣的,這個API不過是做了一點封裝,大致代碼如下:

[javascript] view plain copy
  1. function loadData(options)  
  2. {  
  3.     // 從本地緩存中讀取,很快  
  4.     var dataInCache = U.loadDataFromCache(options.serviceId);  
  5.     if(dataInCache)  
  6.     {  
  7.         options.success(dataInCache);  
  8.     }  
  9.     else  
  10.     {  
  11.         //異步ajax  
  12.         U.readDataFromServer(options.serviceId, options.data, function(response){  
  13.             options.success(response);  
  14.         });  
  15.     }  
  16. }  

由于緩存的影響,$scope.loadListFromService()變得不再那么可控,如果本地已經(jīng)有緩存了,那直接讀取緩存是很快的,這個時候不需要手動$apply;如果是第一次,本地沒有緩存,那么就變成了情況1,我們需要手動$apply。顯然調(diào)用loadData()函數(shù)的地方,不需要也不應(yīng)該關(guān)注到底有沒有緩存的存在,這個時候判斷需要不要手動$apply就沒有那么容易的。簡單粗暴的方式,不管怎么樣都手動調(diào)用下$scope.$apply(),這樣功能不會有問題,但是日志中就不可避免要出現(xiàn)文中開頭提到的錯誤。


angular中的$scope中提供了一個$$phase變量,如果這個變量的值是"$digest" 或者"$apply",就代表angular自身已經(jīng)在做臟值檢測了,不需要我們再去調(diào)用$apply或者$digest;否則的話就需要我們手動調(diào)用$apply或者$digest了。利用這個屬性,我們就可以方便解決上面的錯誤了,判斷一下唄。下面是一個工具函數(shù),好理解吧。

[plain] view plain copy
  1. function safeApply(scope, fn) {  
  2.     (scope.phase || scope.$root.phase) ? fn() : scope.$apply(fn);  
  3. }  


最后提一下,$digest、$apply、$$phase這些屬性或者方法其實都是$scope中的私有的,最好不要使用。如果你用到了這些方法,基本可以斷言你的代碼存在問題,沒有按照angular的方式來組織代碼。比如情況1中的setTimeout,完全可以用angular中的$timeout代替,這才是推薦的方式,而不是通過$apply來補救。

  1. <html>  
  2.   <head>  
  3.     <script src="jquery-1.11.1.min.js"></script>  
  4.     <script src="angular.js"></script>    
  5.     <script>  
  6.           
  7.         var myModule = angular.module('myModule', []);    
  8.         myModule.controller("ctrl_1",function($scope, $timeout){  
  9.             $scope.text = "place";  
  10.               
  11.             $timeout(function(){  
  12.                 $scope.text = "value setted after time out";  
  13.             },1000);  
  14.           
  15.         });   
  16.           
  17.         $(function(){  
  18.             angular.bootstrap($("#div1")[0], ["myModule"]);   
  19.               
  20.         })  
  21.     </script>  
  22.   </head>  
  23.   <body>  
  24.     <div id="div1" ng-controller="ctrl_1">  
  25.         <div>{{text}}</div>  
  26.         <input id="btn" type="button" value="jquery-event"></input>       
  27.     </div>    
  28.   </body>  
  29. </html>  

所以解決“$apply already in progress”最好的方式,就是不要使用$scope.$apply()或者$scope.$digest()。


參考文章:Prevent error $digest already in progress when calling $scope.$apply()




本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
AngularJS1:directive和controller如何通信
一步一步弄懂a(chǎn)ngularJS基礎(chǔ)
AngularJS開發(fā)指南29:將服務(wù)注入到控制器中 | AngularJS中文社區(qū)
AngularJs路由:ngRoute
使用超動感HTML & JS開發(fā)WEB應(yīng)用! | AngularJS中文社區(qū)
AngularJS自學之路(一)
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服