国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

AngularJS報錯$apply already in progress的解決方法分析

2019-11-19 17:46:30
字體:
來源:轉載
供稿:網友

本文實例分析了AngularJS報錯$apply already in progress的解決方法。分享給大家供大家參考,具體如下:

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

Error: [$rootScope:inprog] $apply already in progresshttp://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框架本身已經在做臟數據檢測了,我們沒有必要再手動調用$apply或者$digest。這里自然而然出現了一個疑問:什么時候需要我們手動調用$apply或者$digest,什么時候不需要呢?這是個好問題,我現在也不知道,目前我只能列出自己在項目中遇到的2種需要手動調用$apply的情況。

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

<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不能檢測到數據變化是正常的。

<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,這看起來很簡單,實際上并不是這樣的??匆欢挝覀冺椖恐械拇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()這個函數很像ajax回調,確實是這樣的,這個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()變得不再那么可控,如果本地已經有緩存了,那直接讀取緩存是很快的,這個時候不需要手動$apply;如果是第一次,本地沒有緩存,那么就變成了情況1,我們需要手動$apply。顯然調用loadData()函數的地方,不需要也不應該關注到底有沒有緩存的存在,這個時候判斷需要不要手動$apply就沒有那么容易的。簡單粗暴的方式,不管怎么樣都手動調用下$scope.$apply(),這樣功能不會有問題,但是日志中就不可避免要出現文中開頭提到的錯誤。

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

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相關內容感興趣的讀者可查看本站專題:《AngularJS入門與進階教程》及《AngularJS MVC架構總結

希望本文所述對大家AngularJS程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 长寿区| 彰武县| 鹤岗市| 岚皋县| 芦溪县| 敦煌市| 上虞市| 阳江市| 姜堰市| 武汉市| 垦利县| 仙居县| 哈巴河县| 武威市| 罗山县| 鸡东县| 宁海县| 三亚市| 邹平县| 泾川县| 滦南县| 奉化市| 新民市| 鹿邑县| 临安市| 兴和县| 广宗县| 吉木乃县| 玉龙| 清镇市| 丹江口市| 社旗县| 古田县| 临朐县| 华宁县| 大连市| 航空| 华亭县| 连平县| 昌图县| 丹棱县|