7

设置:我想要一个服务,多个控制器可以查询使用 $http 提取的数据。最初的解决方案是使用这里建议的承诺。

问题:每次控制器查询服务时,服务都会返回一个 $http 承诺,从而导致多个查询一遍又一遍地从远程服务器中提取相同的数据。

解决方案:服务函数返回数据或承诺,如下所示。并由控制器检查并采取相应措施。

app.factory('myService', function($http) {
    var items = [];
    var myService = {
        getItems: function() {
            // if items has content, return items; otherwise, return promise.
            if (items.length > 0) {
                return items;
            } else {     
                var promise = $http.get('test.json').then(function (response) {
                    // fill up items with result, so next query just returns items.
                    for(var i=0;i<response.data.length;i++){
                        items.push(response.data[i]);
                    }
                    return items;
                });
                // Return the promise to the controller
                return promise;
            }
     };
     return myService;
});

因此,当控制器需要该数据时,控制器只会执行以下操作:

app.controller('MainCtrl', function( myService,$scope) {
    var promiseOrData = myService.async();
    // Check whether result is a promise or data.
    if ( typeof promiseOrData.then === 'function'){
        // It's a promise.  Use then().
        promiseOrData.then( function(data ){
            $scope.data = data;
        });
    } else {
        // It's data.
        $scope.data = data;
    }
});

所以问题是:有没有更好的方法来做到这一点?对于许多控制器,这种方法会有很多重复的代码。理想情况下,控制器将直接向服务查询数据。

谢谢!

4

2 回答 2

12

$http 返回一个 promise,我们可以使用它而不是用 $q 创建一个新的。一旦 promise 被解决,我们就可以继续返回它。

.factory('myService', ['$http','$q', function($http, $q) {
    var items = [];
    var last_request_failed = true;
    var promise = undefined;
    return {
        getItems: function() {
            if(!promise || last_request_failed) {
                promise = $http.get('test.json').then(
                function(response) {
                    last_request_failed = false;
                    items = response.data;
                    return items;
                },function(response) {  // error
                    last_request_failed = true;
                    return $q.reject(response);
                });
            }
            return promise;
        },
    };
}])

在您的控制器中:

myService.getItems().then( 
    function(data) { $scope.data = data; }
);
于 2013-08-09T01:09:45.710 回答
1

创建自己的 Promise,解析为缓存数据或获取的数据。

app.factory('myService', function($http, $q) {
    var items = [];
    var myService = {
        getItems: function() {
            var deferred =  $q.defer();

            if (items.length > 0) {
                 //resolve the promise with the cached items
                deferred.resolve(items);
            } else {     
                $http.get('test.json').then(function (response) {
                    // fill up items with result, so next query just returns items.
                    for(var i=0;i<response.data.length;i++){
                        items.push(response.data[i]);
                    }
                    //resolve the promise with the items retrieved
                    deferred.resolve(items);
                },function(response){
                   //something went wrong reject the promise with a message
                   deferred.reject("Could not retrieve data!"); 
                });


            }
         // Return the promise to the controller
         return deferred.promise;
     };
     return myService;
});

然后在你的控制器中使用 promise。

app.controller('MainCtrl', function( myService,$scope) {
    var promiseOrData = myService.getItems();

        promiseOrData.then( function(data){
            $scope.data = data;
        },
        function(data){
            // should log "Could not retrieve data!"
            console.log(data)
        });

});
于 2013-08-09T00:54:45.743 回答