下面這種promise的用法,我從第一篇$http筆記到$resource筆記中,一直都有用到:
HttpREST.factory('cardResource',function($resource){
return $resource('/card/user/:userID/:id',{userID:123,id:'@id'},{charge:{method:'POST',params:{charge:true},isArray:false}})
});
HttpREST.factory('httpCard',function($q,cardResource){
return {
getById:function(cardID){
var defer = $q.defer();
cardResource.get({id:cardID},function(data,headers){
defer.resolve(data);
},function(data,headers){
defer.reject(data);
});
return defer.promise
}
}
});
$scope.card_1 = httpCard.getById(1);
<span>{{card_1['name']}}</span> <span>{{card_1['amount']}}</span>
這樣做的目的很顯然,由於后台返回數據需要時間,所以對card_1的賦值應該是異步的,所以getById方法返回的是一個promise,所以,card_1其實也是一個promise,我們把它打印出來可以看到:
1.同步打印:(還不等到后台返回數據就打印)
$scope.card_1 = httpCard.getById(1);
console.log($scope.card_1);

2.異步打印:(等到后台返回數據以后打印)
$scope.card_1 = httpCard.getById(1); $scope.card_1.then(function(){console.log($scope.card_1)});

可以看到,同步打印的card_1,它的$$v是undefined,因為后台還沒有返回數據,但異步打印的card_1,它的$$v就是請求后返回的數據.
問題就出現了,card_1只有一個$$v屬性和一個then方法,它並沒有name屬性,也沒有amount屬性,但是在視圖中,<span>{{card_1['name']}}</span>確實渲染了.雖然我沒有看過源代碼,但是可以推測,視圖渲染card_1的時候,是使用了card_1的$$v對象來進行渲染的.所以訪問card_1['name'],其實是訪問了card_1的$$v['name'].
那么,如果card_1發生變化的時候,又是怎么處理的呢? 我嘗試了以下操作:
$scope.updataCard = function(){ $scope.card_1.name='工商銀行'; //視圖不會發生變化 $scope.card_1.$save() //card_1沒有$save方法 };
發現直接操作card_1.name屬性,雖然card_1的name屬性確實發生了變化,但是,在視圖中它並沒有任何的變化.可見,視圖對於promise對象,監測的依然是它的$$v對象的屬性的變化,而它自己的屬性變化是沒有任何反應的.另外,card_1是promise對象,不是$resource返回的對象,card_1的$$v才是,所以,card_1當然也沒有$save方法
那么,如果我要更新card_1,修改card_1,到底應該怎么做的? 說到底,card_1的真身就是card_1的$$v對象,so,想要修改card_1,就要修改它的$$v對象:
$scope.updataCard = function(){ $scope.card_1.$$v.name='工商銀行'; $scope.card_1.$$v.$save(); };
這樣做,視圖就會被更新.但是這樣做有一個問題,上面已經看到了,$$v對象是在請求已經得到響應,得到返回的數據的時候才有的,在沒有得到響應前,$$v是undefined.所以,如果在還沒有得到響應前就執行了updataCard函數,這段代碼就會有問題.so,最好的方法是放在promise的then方法的回調函數的參數里:
$scope.updataCard = function(){ $scope.card_1.then(function(data){ data.name='工商銀行'; data.$save() }); };
promise對象有一個then方法,then方法了接受三個回調,詳細參考:http://www.cnblogs.com/liulangmao/p/3907571.html ,這里只寫一個成功的回調,回調的參數data,也就是promise對象的$$v對象,then函數會在響應成功后被調用.所以,即便還沒有得到響應就觸發了updataCard方法,修改的操作還是會等到響應收到后才執行,這就是異步.
注意,這里的card_1是直接通過$resource返回得到的promise,但如果是通過angular路由的resolve方法返回的對象,在resolve的時候已經取了promise對象的$$v對象,然后再注入到控制器中.這樣得到的資源就不再是promise對象了,而已經是promise的$$v對象,后面都正常操作就可以了.
