欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Angular.js中$apply()和$digest()的深入理解

 更新時(shí)間:2016年10月13日 10:16:26   投稿:daisy  
相信大家都知道$digest()和$apply()是AngularJS中的兩個(gè)核心并且有時(shí)候容易引人誤解的部分。我們需要深入理解這兩者是如何運(yùn)作的,從而才能理解AngularJS本身是如何運(yùn)作的。本文的目的就是介紹$digest()和$apply()是如何確確實(shí)實(shí)的對(duì)你有用的。下面來(lái)一起看看吧。

$apply()和$digest()介紹

AngularJS提供了一個(gè)非??岬奶匦越凶鲭p向數(shù)據(jù)綁定(Two-way Data Binding),這個(gè)特性大大簡(jiǎn)化了我們的代碼編寫(xiě)方式。數(shù)據(jù)綁定意味著當(dāng)View中有任何數(shù)據(jù)發(fā)生了變化,那么這個(gè)變化也會(huì)自動(dòng)地反饋到scope的數(shù)據(jù)上,也即意味著scope模型會(huì)自動(dòng)地更新。類似地,當(dāng)scope模型發(fā)生變化時(shí),view中的數(shù)據(jù)也會(huì)更新到最新的值。那么AngularJS是如何做到這一點(diǎn)的呢?當(dāng)你寫(xiě)下表達(dá)式如 時(shí),AngularJS在幕后會(huì)為你在scope模型上設(shè)置一個(gè)watcher,它用來(lái)在數(shù)據(jù)發(fā)生變化的時(shí)候更新view。

這里的watcher和你會(huì)在AngularJS中設(shè)置的watcher是一樣的:

$scope.$watch('aModel', function(newValue, oldValue) {
 //update the DOM with newValue
});

傳入到$watch()中的第二個(gè)參數(shù)是一個(gè)回調(diào)函數(shù),該函數(shù)在aModel的值發(fā)生變化的時(shí)候會(huì)被調(diào)用。當(dāng)aModel發(fā)生變化的時(shí)候,這個(gè)回調(diào)函數(shù)會(huì)被調(diào)用來(lái)更新view這一點(diǎn)不難理解,但是,還存在一個(gè)很重要的問(wèn)題!AngularJS是如何知道什么時(shí)候要調(diào)用這個(gè)回調(diào)函數(shù)呢?換句話說(shuō),AngularJS是如何知曉aModel發(fā)生了變化,才調(diào)用了對(duì)應(yīng)的回調(diào)函數(shù)呢?它會(huì)周期性的運(yùn)行一個(gè)函數(shù)來(lái)檢查scope模型中的數(shù)據(jù)是否發(fā)生了變化嗎?好吧,這就是$digest循環(huán)的用武之地了。

在$digest循環(huán)中,watchers會(huì)被觸發(fā)。當(dāng)一個(gè)watcher被觸發(fā)時(shí),AngularJS會(huì)檢測(cè)scope模型,如何它發(fā)生了變化那么關(guān)聯(lián)到該watcher的回調(diào)函數(shù)就會(huì)被調(diào)用。

那么,下一個(gè)問(wèn)題就是$digest循環(huán)是在什么時(shí)候以各種方式開(kāi)始的?

在調(diào)用了$scope.$digest()后,$digest循環(huán)就開(kāi)始了。假設(shè)你在一個(gè)ng-click指令對(duì)應(yīng)的handler函數(shù)中更改了scope中的一條數(shù)據(jù),此時(shí)AngularJS會(huì)自動(dòng)地通過(guò)調(diào)用$digest()來(lái)觸發(fā)一輪$digest循環(huán)。當(dāng)$digest循環(huán)開(kāi)始后,它會(huì)觸發(fā)每個(gè)watcher。這些watchers會(huì)檢查scope中的當(dāng)前model值是否和上一次計(jì)算得到的model值不同。如果不同,那么對(duì)應(yīng)的回調(diào)函數(shù)會(huì)被執(zhí)行。調(diào)用該函數(shù)的結(jié)果,就是view中的表達(dá)式內(nèi)容(譯注:諸如)會(huì)被更新。除了ng-click指令,還有一些其它的built-in指令以及服務(wù)來(lái)讓你更改models(比如ng-model,$timeout等)和自動(dòng)觸發(fā)一次$digest循環(huán)。

目前為止還不錯(cuò)!但是,有一個(gè)小問(wèn)題。在上面的例子中,AngularJS并不直接調(diào)用$digest(),而是調(diào)用$scope.$apply() ,后者會(huì)調(diào)用$rootScope.$digest() 。因此,一輪$digest循環(huán)在$rootScope開(kāi)始,隨后會(huì)訪問(wèn)到所有的children scope中的watchers。

現(xiàn)在,假設(shè)你將ng-click指令關(guān)聯(lián)到了一個(gè)button上,并傳入了一個(gè)function名到ng-click上。當(dāng)該button被點(diǎn)擊時(shí),AngularJS會(huì)將此function包裝到一個(gè)wrapping function中,然后傳入到$scope.$apply() 。因此,你的function會(huì)正常被執(zhí)行,修改models(如果需要的話),此時(shí)一輪$digest循環(huán)也會(huì)被觸發(fā),用來(lái)確保view也會(huì)被更新。

$scope.$apply()會(huì)自動(dòng)地調(diào)用$rootScope.$digest() 。$apply()方法有兩種形式。第一種會(huì)接受一個(gè)function作為參數(shù),執(zhí)行該function并且觸發(fā)一輪$digest循環(huán)。第二種會(huì)不接受任何參數(shù),只是觸發(fā)一輪$digest循環(huán)。我們馬上會(huì)看到為什么第一種形式更好。

什么時(shí)候手動(dòng)調(diào)用$apply()方法?

如果AngularJS總是將我們的代碼wrap到一個(gè)function中并傳入$apply() ,以此來(lái)開(kāi)始一輪$digest循環(huán),那么什么時(shí)候才需要我們手動(dòng)地調(diào)用$apply()方法呢?實(shí)際上,AngularJS對(duì)此有著非常明確的要求,就是它只負(fù)責(zé)對(duì)發(fā)生于AngularJS上下文環(huán)境中的變更會(huì)做出自動(dòng)地響應(yīng)(即,在$apply()方法中發(fā)生的對(duì)于models的更改)。AngularJS的built-in指令就是這樣做的,所以任何的model變更都會(huì)被反映到view中。但是,如果你在AngularJS上下文之外的任何地方修改了model,那么你就需要通過(guò)手動(dòng)調(diào)用$apply()來(lái)通知AngularJS。這就像告訴AngularJS,你修改了一些models,希望AngularJS幫你觸發(fā)watchers來(lái)做出正確的響應(yīng)。

比如,如果你使用了JavaScript中的setTimeout()來(lái)更新一個(gè)scope model,那么AngularJS就沒(méi)有辦法知道你更改了什么。這種情況下,調(diào)用$apply()就是你的責(zé)任了,通過(guò)調(diào)用它來(lái)觸發(fā)一輪$digest循環(huán)。類似地,如果你有一個(gè)指令用來(lái)設(shè)置一個(gè)DOM事件listener并且在該listener中修改了一些models,那么你也需要通過(guò)手動(dòng)調(diào)用$apply()來(lái)確保變更會(huì)被正確的反映到view中。

讓我們來(lái)看一個(gè)例子。加入你有一個(gè)頁(yè)面,一旦該頁(yè)面加載完畢了,你希望在兩秒鐘之后顯示一條信息。你的實(shí)現(xiàn)可能是下面這個(gè)樣子的:

<body ng-app="myApp">
 <div ng-controller="MessageController">
 Delayed Message: {{message}}
 </div>
</body>
/* What happens without an $apply() */

angular.module('myApp',[]).controller('MessageController', function($scope) {

 $scope.getMessage = function() {
 setTimeout(function() {
  $scope.message = 'Fetched after 3 seconds';
  console.log('message:'+$scope.message);
 }, 2000);
 }

 $scope.getMessage();

});

通過(guò)運(yùn)行這個(gè)例子,你會(huì)看到過(guò)了兩秒鐘之后,控制臺(tái)確實(shí)會(huì)顯示出已經(jīng)更新的model,然而,view并沒(méi)有更新。原因也許你已經(jīng)知道了,就是我們忘了調(diào)用$apply()方法。因此,我們需要修改getMessage() ,如下所示:

/* What happens with $apply */
angular.module('myApp',[]).controller('MessageController', function($scope) {

 $scope.getMessage = function() {
 setTimeout(function() {
  $scope.$apply(function() {
  //wrapped this within $apply
  $scope.message = 'Fetched after 3 seconds';
  console.log('message:' + $scope.message);
  });
 }, 2000);
 }

 $scope.getMessage();

});

如果你運(yùn)行了上面的例子,你會(huì)看到view在兩秒鐘之后也會(huì)更新。唯一的變化是我們的代碼現(xiàn)在被wrapped到了$scope.$apply()中,它會(huì)自動(dòng)觸發(fā)$rootScope.$digest() ,從而讓watchers被觸發(fā)用以更新view。

順便提一下,你應(yīng)該使用$timeout service來(lái)代替setTimeout() ,因?yàn)榍罢邥?huì)幫你調(diào)用$apply() ,讓你不需要手動(dòng)地調(diào)用它。

而且,注意在以上的代碼中你也可以在修改了model之后手動(dòng)調(diào)用沒(méi)有參數(shù)的$apply() ,就像下面這樣:

$scope.getMessage = function() {
 setTimeout(function() {
 $scope.message = 'Fetched after two seconds';
 console.log('message:' + $scope.message);
 $scope.$apply(); //this triggers a $digest
 }, 2000);
};

以上的代碼使用了$apply()的第二種形式,也就是沒(méi)有參數(shù)的形式。需要記住的是你總是應(yīng)該使用接受一個(gè)function作為參數(shù)的$apply()方法。這是因?yàn)楫?dāng)你傳入一個(gè)function到$apply()中的時(shí)候,這個(gè)function會(huì)被包裝到一個(gè)try…catch塊中,所以一旦有異常發(fā)生,該異常會(huì)被$exceptionHandler service處理。

$digest循環(huán)會(huì)運(yùn)行多少次?

當(dāng)一個(gè)$digest循環(huán)運(yùn)行時(shí),watchers會(huì)被執(zhí)行來(lái)檢查scope中的models是否發(fā)生了變化。如果發(fā)生了變化,那么相應(yīng)的listener函數(shù)就會(huì)被執(zhí)行。這涉及到一個(gè)重要的問(wèn)題。如果listener函數(shù)本身會(huì)修改一個(gè)scope model呢?AngularJS會(huì)怎么處理這種情況?

答案是$digest循環(huán)不會(huì)只運(yùn)行一次。在當(dāng)前的一次循環(huán)結(jié)束后,它會(huì)再執(zhí)行一次循環(huán)用來(lái)檢查是否有models發(fā)生了變化。這就是臟檢查(Dirty Checking),它用來(lái)處理在listener函數(shù)被執(zhí)行時(shí)可能引起的model變化。因此,$digest循環(huán)會(huì)持續(xù)運(yùn)行直到model不再發(fā)生變化,或者$digest循環(huán)的次數(shù)達(dá)到了10次。因此,盡可能地不要在listener函數(shù)中修改model。

$digest循環(huán)最少也會(huì)運(yùn)行兩次,即使在listener函數(shù)中并沒(méi)有改變?nèi)魏蝝odel。正如上面討論的那樣,它會(huì)多運(yùn)行一次來(lái)確保models沒(méi)有變化。

總結(jié)

我希望這篇文章解釋清楚了$apply和$digest。需要記住的最重要的是AngularJS是否能檢測(cè)到你對(duì)于model的修改。如果它不能檢測(cè)到,那么你就需要手動(dòng)地調(diào)用$apply()。以上就是這篇文章的全部?jī)?nèi)容,大家都學(xué)會(huì)了嗎?希望這篇文章的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。

相關(guān)文章

  • 淺談angularJS2中的界面跳轉(zhuǎn)方法

    淺談angularJS2中的界面跳轉(zhuǎn)方法

    今天小編就為大家分享一篇淺談angularJS2中的界面跳轉(zhuǎn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Angular限制input框輸入金額(是小數(shù)的話只保留兩位小數(shù)點(diǎn))

    Angular限制input框輸入金額(是小數(shù)的話只保留兩位小數(shù)點(diǎn))

    最近做項(xiàng)目遇到這樣的需求輸入框要求輸入金額,只能輸入數(shù)字,可以是小數(shù),必須保留小數(shù)點(diǎn)后兩位。下面分為兩部分代碼給大家介紹實(shí)現(xiàn)代碼,需要的的朋友參考下吧
    2017-07-07
  • Angularjs之ngModel中的值驗(yàn)證綁定方法

    Angularjs之ngModel中的值驗(yàn)證綁定方法

    今天小編就為大家分享一篇Angularjs之ngModel中的值驗(yàn)證綁定方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • AngularJS過(guò)濾器詳解及示例代碼

    AngularJS過(guò)濾器詳解及示例代碼

    本文主要介紹AngularJS過(guò)濾器,這里整理了詳細(xì)的資料和提供了示例代碼及實(shí)例效果圖,有興趣的小伙伴可以參考下
    2016-08-08
  • Angular2 父子組件數(shù)據(jù)通信實(shí)例

    Angular2 父子組件數(shù)據(jù)通信實(shí)例

    這篇文章主要介紹了Angular2 父子組件數(shù)據(jù)通信實(shí)例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-06-06
  • Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]的寫(xiě)法

    Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]的寫(xiě)法

    本篇文章主要介紹了Angular 2 ngForm中的ngModel、[ngModel]和[(ngModel)]的區(qū)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • AngularJS自定義控件實(shí)例詳解

    AngularJS自定義控件實(shí)例詳解

    這篇文章主要介紹了AngularJS自定義控件,結(jié)合實(shí)例形式詳細(xì)分析了AngularJS自定義指令與模板操作的相關(guān)函數(shù)與使用技巧,需要的朋友可以參考下
    2016-12-12
  • AngularJS實(shí)現(xiàn)的回到頂部指令功能實(shí)例

    AngularJS實(shí)現(xiàn)的回到頂部指令功能實(shí)例

    這篇文章主要介紹了AngularJS實(shí)現(xiàn)的回到頂部指令功能,結(jié)合實(shí)例形式分析了AngularJS返回到頂部功能的具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2017-05-05
  • Angular.js中處理頁(yè)面閃爍的方法詳解

    Angular.js中處理頁(yè)面閃爍的方法詳解

    我們?cè)趹?yīng)用的頁(yè)面或者組件需要加載數(shù)據(jù)時(shí),瀏覽器和angular渲染頁(yè)面都需要消耗一定的時(shí)間。這里的間隔可能很小,甚至讓人感覺(jué)不到區(qū)別;但也可能很長(zhǎng),這樣會(huì)導(dǎo)致讓我們的用戶看到了沒(méi)有被渲染過(guò)的頁(yè)面。本文將介紹Angular.js中處理頁(yè)面閃爍的方法。
    2017-03-03
  • AngularJS執(zhí)行流程詳解

    AngularJS執(zhí)行流程詳解

    本文主要介紹了AngularJS的執(zhí)行流程。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02

最新評(píng)論