初學angular的時候,咱們在使用中常常遇到更改scope裏的值,可是model沒有相應的更新。因而咱們發現angular有一個$apply()方法,來update咱們的model.可是咱們使用事後,有時候控制檯會報出錯誤:html
Error: $digest / $apply already in progress。angularjs
而後咱們百度獲得的解決方案是:express
if(!$scope.$$phase) { //$digest or $apply }
一直一來,我在我初學angular後作的項目裏也是這麼幹的。直到某一天我看到了有人說:
app
而後我開始反思,個人程序是是否是哪裏寫的有問題?在我翻看了不少大神的文章後,我大體理解了。函數
爲何咱們會使用到$apply()?oop
通常狀況,咱們在 controller初始化、使用$http的callbacks、相似ng-click這類的ng-*事件時,angular都會用$apply()包起來當裏面的function或者一個Angular expression string執行後,就會去調用$scope.$digest()更新數據的綁定。因此是不須要你去主動調用$apply()的,且你在$apply()裏面調用$apply()將會拋錯的。就是如大家看到的$digest / $apply already in progress。spa
若是咱們用到了$apply()那麼應該是如下狀況:code
a. 代碼處於$digest loop(更新週期)外,好比在"link"指令(directive)響應函數內部使用。也就是說,只能在$controller以外調用$apply,這樣它就能夠訪問到HTML或其餘控制器的聲明代碼 - 好比apply調用link指令並觸發相應功能,這時侯是確定在$digest loop以外的。htm
b. 在你的代碼塊裏面還包含有新的函數塊,好比:事件
function Ctrl($scope) { $scope.message = "Waiting 2000ms for update"; setTimeout(function () { $scope.message = "Timeout called!"; // AngularJS unaware of update to $scope }, 2000); }
message在內部匿名函數內被賦值,是沒法觸發angular的髒值檢測的,正確的作法就是:
function Ctrl($scope) { $scope.message = "Waiting 2000ms for update"; setTimeout(function () { $scope.$apply(function () { $scope.message = "Timeout called!"; }); }, 2000); }
如何正確使用$apply()?
$scope.$apply()接收一個函數或Angular表達式字符串,並執行它,而後調用 $scope.$digest()來更新全部綁定或偵聽者。
但有些人的作法是像我最初同樣,直接使用
if(!$scope.$$phase) { //$digest or $apply }
這個作法就會致使若是你的代碼出錯,而後又沒有相應的處理機制那麼程序就會卡死在那裏。
$apply不只僅執行你的代碼,它內部的try / catch語句讓你的錯誤老是能被捕捉到,而且$digist是最後的保障,它意爲着即便一個錯誤拋出,它仍能運行。因此正確的作法是:
$scope.$apply(function () { $scope.message = "Timeout called!"; });
以上是我觀點,若有錯誤,請指證!