我的应用中有一个处理API调用的基本工厂。目前我正在使用表格:
.factory('apiFactory', function($http){
var url = 'http://192.168.22.8:8001/api/v1/';
return {
getReports: function() {
return $http.get(url+'reports').then(function(result) {
return result;
});
},
getReport: function(id) {
return $http.get(url+'report/'+id).then(function(result) {
return result;
});
}
}
})
在我的控制器中,我正在处理这样的承诺:
.controller('exampleController', function($scope, apiFactory) {
apiFactory.getReports().then(
function(answer) {
if (answer.status==200){
if (answer.data.status == "error"){
// DISPLAY ERROR MESSAGE
console.log(answer.data.msg);
}
} else{
// THROW error
console.log('error: ', answer);
}
},
function(error){
console.log('error: ', answer);
}
);
}
}
})
似乎我可以将承诺处理转移到我的工厂而不是在我的控制器中进行,但我不确定除了较小的控制器之外是否还有其他好处。
有人可以解释有关此模式的最佳做法吗?
答案 0 :(得分:10)
最终由您决定要向服务的调用者提供多少数据。如果需要,你肯定可以将HTTP响应对象返回给调用者,让他们处理响应(如果承诺得到解决而不是被拒绝,那么,顺便说一句,总是HTTP 2xx)。
但是如果你想将调用者与数据的具体方式隔离开来(可能是缓存,或通过其他机制提供),如果你需要对数据进行后处理,那么建议你处理服务中的回应。
以下是一个例子:
.factory("apiService", function($http, $q){
var url = 'http://192.168.22.8:8001/api/v1/';
return {
getReports: function() {
return $http.get(url+'reports').then(function(result) {
var data = result.data;
if (data === "something I don't accept"){
return $q.reject("Invalid data");
}
var processedData = processData(data);
return processedData;
})
.catch(function(err){
// for example, "re-throw" to "hide" HTTP specifics
return $q.reject("Data not available");
})
},
// same idea for getReport
}
});
然后控制器不需要关心底层机制 - 它得到的只是数据或拒绝。
.controller('exampleController', function($scope, apiService) {
apiService.getReports()
.then(function(reports){
$scope.reports = reports; // actual reports data
});
})
<强>题外话:强>
请注意我是如何将服务名称从"apiFactory"
更改为"apiService"
的。我想指出这一点,以消除可能的误解。无论您使用.factory
还是.service
还是.value
,您获得的注射剂始终是 服务 实例。 .factory
只是如何实例化此服务的机制,因此名称"apiFactory"
是用词不当。这里唯一的“工厂”是您注册.factory
的功能(当然可以是匿名的):
.factory("fooSvc", function fooSvcFactory(){
return {
getFoo: function(){...}
}
})
答案 1 :(得分:2)
最好将所有数据保存在工厂内。这使控制器不受状态影响,并且不再关心工厂的工作方式。如果您更改数据的获取方式(例如,不使用$ http),您的控制器应该不关心,因为它只调用getReport()和
一个很好的解释(参见“解析模型数据,控制器中没有回调arg绑定”): http://toddmotto.com/rethinking-angular-js-controllers/
答案 2 :(得分:2)
简答:处理工厂中的承诺。
<强>为什么吗
如果您在Controller中处理承诺时遇到的问题:
假设您有5个使用相同工厂的控制器。现在让我们假设您希望在未正确解析promise时处理错误。因此,在第一个控制器中,您编写了一个错误回调(或者更准确地说,捕获(异常),因为您正在处理promises),它会显示一条带有错误的警报消息。当promise失败时,此控制器将显示带有错误消息的警报。到现在为止还挺好?对。可是等等!那4个控制器怎么样?你还没有处理它们中的错误。所以现在你最终从第一个控制器&amp;中复制错误处理代码了。将它粘贴在4个控制器的其余部分中。
现在开始有趣了。想象一下,您想要在错误状态下更改逻辑。也许您只想在控制台中记录错误,或者显示烤箱消息。所以你去第一个控制器&amp;更新代码。你认为你完成了吗?没有!!!有4个其他控制器显示警报消息(请记住,您之前粘贴了第一个控制器的代码???)。所以现在,您尝试通过粘贴新的错误消息逻辑来更新其余控制器。想想你需要更新的所有控制器,如果你有更多!累人,不是吗?
为什么要解决工厂中的承诺:
现在让我们说您在服务中编写错误处理逻辑,并且所有控制器都在使用此服务。如果承诺在此服务中失败,您已编写代码以显示警报。如果承诺损坏,所有控制器现在将开始显示此警报。将来,如果您希望更新错误逻辑,只需更新服务中的错误逻辑即可。您的所有控制器都将自动开始使用此更新的逻辑,而您无需付出更多努力。这样,你节省了大量的时间。
所以想一想:
所有控制器中的出厂变化1变化1(可能是1或更多)
我肯定会保证在Factory中进行1次更改,因为这有助于仅使用一次简单的更改重用我的逻辑。我的所有控制器都将开始使用新逻辑。控制器应该是苗条的,精益的和清洁。工厂&amp;服务应该是可重用的。出于这种可重用性的原因,我强烈建议您处理工厂/服务中的承诺。