设置:我希望有一个服务,多个控制器可以查询使用$ http提取的数据。最初的解决方案是使用建议here的承诺。
问题:每次控制器查询服务时,服务都会返回$ 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;
}
});
所以问题是:有更好的方法吗?对于许多控制器,这种方法会有很多重复的代码。理想情况下,控制器只是直接在服务中查询数据。
谢谢!
答案 0 :(得分:12)
$ http返回一个promise,我们可以使用它而不是用$ q创建一个新的。一旦承诺得到解决,我们就可以继续回复。
.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; }
);
答案 1 :(得分:1)
创建自己的承诺,解析为缓存数据或获取的数据。
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;
});
然后消耗控制器中的承诺。
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)
});
});