AngularJS報錯$apply already in progress的解決方法分析
本文實例分析了AngularJS報錯$apply already in progress的解決方法。分享給大家供大家參考,具體如下:
如果我們使用了AngularJS中的$scope.$apply()或者$scope.$digest(),我們很可能會遇到類似下面的錯誤,雖然這個錯誤沒有太大影響,但是在日志中看起來還是很不爽的,日志中記錄的異?;蛘咤e誤,就應該是需要關注和解決的問題,否則就沒有必要出現(xiàn)在日志中了。
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)
下面這段代碼就會報上面這個錯誤:
var myModule = angular.module('myModule', []);
myModule.controller("ctrl_1",function($scope){
$scope.value = "aty";
$scope.$apply();
//$scope.$digest();
});
這個錯誤其實很好理解: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)結束,無法檢測到回調(diào)函數(shù)導致數(shù)據(jù)的變化。
<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();//必需手動進行臟值檢測,否則數(shù)據(jù)無法刷新到界面
},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>
這段代碼如果沒有調(diào)用$scope.$apply()的話,數(shù)據(jù)是不會刷新到界面上的。
情況2:在jQuery代碼中修改$scope中的數(shù)據(jù)。這種情況是在angular框架之外操作$scope中的數(shù)據(jù),angular不能檢測到數(shù)據(jù)變化是正常的。
<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的事件處理函數(shù)中,我們能夠通過dom拿到其關聯(lián)的$scope對象,進而修改$scope中的數(shù)據(jù)。這種情況下,也必需要手動調(diào)用$scope.$apply()。
也就是說我們必須要清楚哪兒些情況需要手動$apply,哪兒些情況不需要手動$apply,這看起來很簡單,實際上并不是這樣的??匆欢挝覀冺椖恐械拇a:
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()這個函數(shù)很像ajax回調(diào),確實是這樣的,這個API不過是做了一點封裝,大致代碼如下:
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()變得不再那么可控,如果本地已經(jīng)有緩存了,那直接讀取緩存是很快的,這個時候不需要手動$apply;如果是第一次,本地沒有緩存,那么就變成了情況1,我們需要手動$apply。顯然調(diào)用loadData()函數(shù)的地方,不需要也不應該關注到底有沒有緩存的存在,這個時候判斷需要不要手動$apply就沒有那么容易的。簡單粗暴的方式,不管怎么樣都手動調(diào)用下$scope.$apply(),這樣功能不會有問題,但是日志中就不可避免要出現(xiàn)文中開頭提到的錯誤。
angular中的$scope中提供了一個$$phase變量,如果這個變量的值是"$digest" 或者"$apply",就代表angular自身已經(jīng)在做臟值檢測了,不需要我們再去調(diào)用$apply或者$digest;否則的話就需要我們手動調(diào)用$apply或者$digest了。利用這個屬性,我們就可以方便解決上面的錯誤了,判斷一下唄。下面是一個工具函數(shù),好理解吧。
function safeApply(scope, fn) {
(scope.
phase||scope.$root.
phase) ? fn() : scope.$apply(fn);
}
最后提一下,$digest、$apply、$$phase這些屬性或者方法其實都是$scope中的私有的,最好不要使用。如果你用到了這些方法,基本可以斷言你的代碼存在問題,沒有按照angular的方式來組織代碼。比如情況1中的setTimeout,完全可以用angular中的$timeout代替,這才是推薦的方式,而不是通過$apply來補救。
<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相關內(nèi)容感興趣的讀者可查看本站專題:《AngularJS入門與進階教程》及《AngularJS MVC架構總結》
希望本文所述對大家AngularJS程序設計有所幫助。
- angularJS中$apply()方法詳解
- 淺談angular.js中實現(xiàn)雙向綁定的方法$watch $digest $apply
- AngularJS中的$watch(),$digest()和$apply()區(qū)分
- 全面解析Angular中$Apply()及$Digest()的區(qū)別
- AngularJS中$apply方法和$watch方法用法總結
- Angular項目中$scope.$apply()方法的使用詳解
- angularjs 中$apply,$digest,$watch詳解
- Angular.js中$apply()和$digest()的深入理解
- AngularJS雙向數(shù)據(jù)綁定原理之$watch、$apply和$digest的應用
- Angularjs中的$apply及優(yōu)化使用詳解
相關文章
在AngularJS框架中處理數(shù)據(jù)建模的方式解析
這篇文章主要介紹了在AngularJS框架中處理數(shù)據(jù)建模的方式,作者同時也對AngularJS使用過程中的一些"坑"作了介紹,需要的朋友可以參考下2016-03-03
AngularJS入門教程之數(shù)據(jù)綁定用法示例
這篇文章主要介紹了AngularJS之數(shù)據(jù)綁定用法,結合實例形式分析了AngularJS基于內(nèi)置指令ng-model實現(xiàn)數(shù)據(jù)綁定的操作技巧,需要的朋友可以參考下2016-11-11
AngularJS的ng-repeat指令與scope繼承關系實例詳解
這篇文章主要介紹了AngularJS的ng-repeat指令與scope繼承關系,結合實例形式通過ng-repeat指令詳細分析了scope繼承關系,需要的朋友可以參考下2017-01-01
微信小程序?qū)崿F(xiàn)左右聯(lián)動的實戰(zhàn)記錄
聯(lián)動菜單是大家在開發(fā)小程序經(jīng)常會遇到的一個功能,下面這篇文章主要給大家介紹了關于微信小程序?qū)崿F(xiàn)左右聯(lián)動的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起學習學習吧2018-07-07
AngularJS輔助庫browserTrigger用法示例
這篇文章主要介紹了AngularJS輔助庫browserTrigger用法,結合實例形式分析了輔助庫browserTrigger的功能及單元測試中的使用技巧,需要的朋友可以參考下2016-11-11
Angularjs Ng_repeat中實現(xiàn)復選框選中并顯示不同的樣式方法
今天小編就為大家分享一篇Angularjs Ng_repeat中實現(xiàn)復選框選中并顯示不同的樣式方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09

