angular學習筆記(二十八-附2)-$http,$resource中的promise物件

詩&遠方發表於2014-08-12

下面這種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物件,後面都正常操作就可以了.

 

相關文章