今天,咱們要聊得是Angularjs中的小明星$apply。當咱們數據更新了,可是view層卻沒反應時,總能聽到有人說,用apply吧,而後,懵懂無知的咱們,在賦值代碼後面加了$scope.$apply(),而後就驚喜的發現。噢,真的更新了。 然而,有些時候,編譯器會無情的給你返回html
Error: $digest already in progress
複製代碼
那麼,致使這些現象的緣由時什麼的呢?$apply究竟幹了啥?聽我慢慢道來。jquery
$apply()函數能夠從Angular框架的外部讓表達式在Angular上下文內部執行。app
上面是AngularJs權威教程中的一句話。什麼意思呢? 首先,你要清楚,在原生js或者第三方框架下,修改model,是有可能不會觸發視圖更新的,好比setTimeout、jquery插件。爲何?由於他們脫離了Angularjs的上下文,Angularjs並不能監聽到數據的改變。看例子。框架
html:jquery插件
<p>{{name}}</p>
複製代碼
js:函數
$scope.name="張三";
setTimeout(function(){
$scope.name = '李四';
//$scope.$apply()
},500)
複製代碼
首先,name等於張三,500ms後,我把他賦值爲李四,可是,頁面上並無改變,依然是張三。 而,咱們把$scope.$apply()放開,就正常了,張三成功變爲李四。性能
html:spa
<p>Date: <input type="text" id="datepicker"></p>
<p>
<header>所選日期</header>
{{selectedDate}}
</p>
複製代碼
js:插件
$scope.selectedDate = '';
$( function() {
$( "#datepicker" ).datepicker({
onClose: function( selectedDate ) {
$scope.selectedDate = selectedDate;
// $scope.$apply();
}
});
} );
複製代碼
這是jquery的datepicker插件,當咱們選定日期後,下面的日期應該隨之顯現,而如今卻沒有。這種狀況就必須依靠$apply(),才能更新視圖。code
以上兩種狀況,都由於不處於Angularjs上下文中,致使監聽不到數據的變化。而$apply究竟幹了什麼,才致使數據更新正常了呢?
其實$apply至關於一個觸發器,它的做用就是觸發digest循環,從而更新視圖。
在digest是Angularjs的核心,是它實現了神奇的數據綁定。凡是觸發事件,必會觸發digest循環,好比,咱們數值的ng事件,click啊,change,實際上都是觸發了digest循環。
因此,咱們所作的事,其實就是手動觸發了digest循環。關於digest循環,屬於題外話,這裏不作過多介紹,想深刻了解的同窗,能夠看看書籍,或者百度。
在Angularjs中,除了$apply能夠觸發digest循環外,還有其餘的方法,也能夠觸發此循環。並且$apply每每時最壞的選擇。下面推薦一些更好的選擇。
$scope.$digest()的速度要比$apply要快,由於它只更新當前做用域和子做用域的值,對於父做用域時無論的。而$apply還要評估父做用域,這就大大消耗了性能。
用$timeout去代替你的setTimeout,$timeout做爲Angularjs的自帶服務,固然時更契合Angularjs環境啦。它會隱性觸發digest循環,並且它會延遲執行,會在上一個digest循環完成後的下一刻,觸發digest循環,這樣就不會出現上文所說的
$digest already in progress
複製代碼
咱們把setTime的代碼放到$timeout中
$timeout(function(){
$scope.name = '李四';
},500)
複製代碼
這就能正常工做了,看,沒有討厭的apply了!
最推薦的應該時這個方法了。若是當前正好有一個digest循環在執行,那麼它就會把致使digest循環的操做,放到當前digest循環中去執行。而$timeout是要等到當前digest循環執行完,再執行一次digest循環才能夠。因此evalAsync執行更快,性能更好。咱們能夠像$timeout那樣去調用它,即
$scope.$evalAsync(
function( $scope ) {
console.log( "$evalAsync" );
}
);
複製代碼
以上,就是今天要說的所有內容。Angularjs中還藏着許多奧祕,和更好的使用方法,但願你們能夠深刻地研究,分享出更好的文章。 下面是可執行的代碼,你們能夠探究探究