Angularjs中的$apply及優(yōu)化使用詳解
前言
對于一個在前端屬于純新手的我來說,Javascript都還是一知半解,要想直接上手angular JS,遇到的阻力還真是不少。不過我相信,只要下功夫,即使是反人類的設計也不是什么大的問題。
今天,我們要聊得是Angularjs中的小明星$apply。當我們數據更新了,但是view層卻沒反應時,總能聽到有人說,用apply吧,然后,懵懂無知的我們,在賦值代碼后面加了$scope.$apply()
,然后就驚喜的發(fā)現(xiàn)。噢,真的更新了。
然而,有些時候,編譯器會無情的給你返回
Error: $digest already in progress
那么,導致這些現(xiàn)象的原因時什么的呢?$apply究竟干了啥?聽我慢慢到來。
一.$apply的作用
$apply()函數可以從Angular框架的外部讓表達式在Angular上下文內部執(zhí)行。
上面是AngularJs權威教程中的一句話。什么意思呢?
首先,你要清楚,在原生js或者第三方框架下,修改model,是有可能不會觸發(fā)視圖更新的,比如setTimeout、jquery插件。為什么?因為他們脫離了Angularjs的上下文,Angularjs并不能監(jiān)聽到數據的改變??蠢?。
1.setTimeout
html:
<p>{{name}}</p>
js:
$scope.name="張三"; setTimeout(function(){ $scope.name = '李四'; //$scope.$apply() },500)
首先,name等于張三,500ms后,我把他賦值為李四,但是,頁面上并沒有改變,依然是張三。
而,我們把$scope.$apply()
放開,就正常了,張三成功變?yōu)槔钏摹?/p>
2.第三方插件
html:
<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插件,當我們選定日期后,下面的日期應該隨之顯現(xiàn),而現(xiàn)在卻沒有。這種情況就必須依靠$apply(),才能更新視圖。
以上兩種情況,都因為不處于Angularjs上下文中,導致監(jiān)聽不到數據的變化。而$apply究竟干了什么,才導致數據更新正常了呢?
其實$apply相當于一個觸發(fā)器,它的作用就是觸發(fā)digest循環(huán),從而更新視圖。
在digest是Angularjs的核心,是它實現(xiàn)了神奇的數據綁定。凡是觸發(fā)事件,必會觸發(fā)digest循環(huán),比如,我們數值的ng事件,click啊,change,實際上都是觸發(fā)了digest循環(huán)。
所以,我們所做的事,其實就是手動觸發(fā)了digest循環(huán)。關于digest循環(huán),屬于題外話,這里不做過多介紹,想深入了解的同學,可以看看書籍,或者百度。
二.更好地運用digest循環(huán)
在Angularjs中,除了$apply可以觸發(fā)digest循環(huán)外,還有其他的方法,也可以觸發(fā)此循環(huán)。而且$apply往往時最壞的選擇。下面推薦一些更好的選擇。
1.$digest
$scope.$digest()
的速度要比$apply要快,因為它只更新當前作用域和子作用域的值,對于父作用域時不管的。而$apply還要評估父作用域,這就大大消耗了性能。
2.$timeout
用$timeout去代替你的setTimeout,$timeout作為Angularjs的自帶服務,當然時更契合Angularjs環(huán)境啦。它會隱性觸發(fā)digest循環(huán),而且它會延遲執(zhí)行,會在上一個digest循環(huán)完成后的下一刻,觸發(fā)digest循環(huán),這樣就不會出現(xiàn)上文所說的
$digest already in progress
我們把setTime的代碼放到$timeout中
$timeout(function(){ $scope.name = '李四'; },500)
這就能正常工作了,看,沒有討厭的apply了!
3.$evalAsync
最推薦的應該時這個方法了。如果當前正好有一個digest循環(huán)在執(zhí)行,那么它就會把導致digest循環(huán)的操作,放到當前digest循環(huán)中去執(zhí)行。而$timeout是要等到當前digest循環(huán)執(zhí)行完,再執(zhí)行一次digest循環(huán)才可以。所以evalAsync執(zhí)行更快,性能更好。我們可以像$timeout那樣去調用它,即
$scope.$evalAsync( function( $scope ) { console.log( "$evalAsync" ); } );
以上,就是今天要說的全部內容。Angularjs中還藏著許多奧秘,和更好的使用方法,希望大家可以深入地研究,分享出更好的文章。
下面是可執(zhí)行的代碼,大家可以探究探究:https://codepen.io/hanwolfxue/pen/yEZbYQ
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。
相關文章
Angular統(tǒng)一注入器unified injector簡化依賴關系管理
這篇文章主要為大家介紹了Angular統(tǒng)一注入器unified injector簡化依賴關系管理的使用方法實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-10-10淺析Angular 實現(xiàn)一個repeat指令的方法
這篇文章主要介紹了Angular 實現(xiàn)一個repeat指令的方法,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-07-07AngularJS 將再發(fā)布一個重要版本 然后進入長期支持階段
目前團隊正在開發(fā) AngularJS 1.7.0,而 1.7 的開發(fā)周期將一直持續(xù)到 2018 年 6 月 30 日2018-01-01淺談Angularjs link和compile的使用區(qū)別
下面小編就為大家?guī)硪黄獪\談Angularjs link和compile的使用區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10淺談angular表單提交中ng-submit的默認使用方法
今天小編就為大家分享一篇淺談angular表單提交中ng-submit的默認使用方法。具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09