$digest和$apply
在Angular中,有$apply和$digest兩個函數,我們剛才是通過$digest來讓這個數據應用到界面上。但這個時候,也可以不用$digest,而是使用$apply,效果是一樣的,那么,它們的差異是什么呢?
最直接的差異是,$apply可以帶參數,它可以接受一個函數,然后在應用數據之后,調用這個函數。除此之外,還有別的區別嗎?
在簡單的數據模型中,這兩者沒有本質差別,但是當有層次結構的時候,就不一樣了。考慮到有兩層作用域,我們可以在父作用域上調用這兩個函數,也可以在子作用域上調用,這個時候就能看到差別了。
對於$digest來說,在父作用域和子作用域上調用是有差別的,但是,對於$apply來說,這兩者一樣。我們來構造一個特殊的示例:
var app = angular.module("test", []); app.directive("increasea", function() { return function (scope, element, attr) { element.on("click", function() { scope.a++; scope.$digest(); }); }; }); app.directive("increaseb", function() { return function (scope, element, attr) { element.on("click", function() { scope.b++; scope.$digest(); //這個換成$apply即可 }); }; }); app.controller("OuterCtrl", ["$scope", function($scope) { $scope.a = 1; $scope.$watch("a", function(newVal) { console.log("a:" + newVal); }); $scope.$on("test", function(evt) { $scope.a++; }); }]); app.controller("InnerCtrl", ["$scope", function($scope) { $scope.b = 2; $scope.$watch("b", function(newVal) { console.log("b:" + newVal); $scope.$emit("test", newVal); }); }]); <div ng-app="test"> <div ng-controller="OuterCtrl"> <div ng-controller="InnerCtrl"> <button increaseb>increase b</button> <span ng-bind="b"></span> </div> <button increasea>increase a</button> <span ng-bind="a"></span> </div> </div>
這時候,我們就能看出差別了,在increase b按鈕上點擊,這時候,a跟b的值其實都已經變化了,但是界面上的a沒有更新,直到點擊一次increase a,這時候剛才對a的累加才會一次更新上來。怎么解決這個問題呢?只需在increaseb這個指令的實現中,把$digest換成$apply即可。
當調用$digest的時候,只觸發當前作用域和它的子作用域上的監控,但是當調用$apply的時候,會觸發作用域樹上的所有監控。
因此,從性能上講,如果能確定自己作的這個數據變更所造成的影響范圍,應當盡量調用$digest,只有當無法精確知道數據變更造成的影響范圍時,才去用$apply,很暴力地遍歷整個作用域樹,調用其中所有的監控。
從另外一個角度,我們也可以看到,為什么調用外部框架的時候,是推薦放在$apply中,因為只有這個地方才是對所有數據變更都應用的地方,如果用$digest,有可能臨時丟失數據變更。
轉自: https://github.com/xufei/blog/issues/10