我想知道是否可以在多个级别上处理ngResource返回的$promise
,以便代码是DRY
这是一个简单的例子
aService = function(aResource) {
var error, success;
success = function(response) {
console.log('Service Success');
};
error = function(response) {
console.log('Service Error');
};
this.servicePostReq = function() {
return aResource.save().$promise.then(success, error);
};
return this;
angular.module('app.service').factory('aService', ['aResource', aService]);
到目前为止这个工作正常...当响应正常时它是Service Success
而当响应不正确时它是Service Error
但是当我添加一个使用此aService
的控制器时,如下所示
aController = function(aService) {
var error, success;
success = function(response) {
console.log('Controller Success');
};
error = function(response) {
console.log('Controller Error');
};
this.controllerPostReq = function() {
aService.servicePostReq().then(success, error);
};
return this;
};
angular.module('app.controller').controller('aController', ['aService', aController]);
控制器总是成功......
因此,如果请求返回成功,则输出为
Service Success
Controller Success
如果请求失败,则输出为
Service Error
Controller Success
如何链接承诺,以便我不必为每个使用该服务的控制器添加服务中处理的代码?
答案 0 :(得分:4)
问题是你的服务。改变这个:
this.servicePostReq = function() {
return aResource.save().$promise.then(success, error);
};
对此:
this.servicePostReq = function() {
return aResource.save().$promise.then(success);
};
<强>解释强>
由于您的服务返回aResource.save().$promise.then(success, error)
,它将返回一个包含错误处理程序的新promise。之后,在您的控制器中,您可以像这样添加链。
aService.servicePostReq().then(success, error);
此时完整的承诺链看起来是否展开:
return aResource.save().$promise
.then(successFnFromService, errorFnFromService)
.then(successFnFromController, errorFnFromController);
由于您使用aResource.save()
从errorFnFromService
收到错误,因此此时承诺链基本上是“干净的”,它将继续下一个then
。
通过删除第一个错误处理程序,您可以在以后捕获错误。
处理promise链中的错误的一种更好的方法(通常)是在链的末尾使用单个.catch()。
考虑这个错误代码(尝试在浏览器控制台上运行):
new Promise(
function(resolve, reject){
reject('first');
}).then(
function(result) {
console.log('1st success!', result);
return result;
},
function(err) {
console.log('1st error!', err);
return err;
}
).then(
function(result){
console.log('2nd success!', result);
},
function(err){
console.log("2nd error!", err);
}
);
输出:
1st error! first
2nd success! first
更好的方式:
new Promise(
function(resolve, reject){
reject('first');
}).then(function(result) {
console.log('1st success!', result);
return result;
}).then(function(result){
console.log('2nd success!', result);
// catch error once at the end
}).catch(function(err){
console.log("error!", err);
});
输出:
error! first
在浏览器控制台中尝试这两种操作,并将reject
更改为resolve
以查看它对输出的影响。
答案 1 :(得分:1)
在$q
上添加依赖项,并使用$q.reject
来控制执行......
$q.reject
方法中的aService.error
reject(reason);
创建一个以指定原因解析为已拒绝的承诺。这个api应该用于在一系列承诺中转发拒绝。如果您正在处理承诺链中的最后承诺,您不必担心它。
将deferreds / promises与熟悉的try / catch / throw行为进行比较时,请将reject视为JavaScript中的throw关键字。这也意味着,如果你&#34;赶上&#34;通过promise错误回调发生错误,并且您希望将错误转发给从当前承诺派生的承诺,您必须&#34;重新抛出&#34;返回通过拒绝构建的拒绝错误。
答案 2 :(得分:1)
为了正确链接promise,成功和错误处理程序都应返回一些值。返回值会自动包含在您的新承诺中。这意味着如果出现错误,您必须使用$q.reject
返回被拒绝的承诺。
所以你的服务应该是这样的:
aService = function($q, aResource) {
var error, success;
success = function(response) {
// important! return a value, handlers down the chain will
// execute their success handlers and receive this value
return 'Service Success';
};
error = function(response) {
// important! return a REJECTION, handlers down the chain will
// execute their error handlers and receive this value
return $q.reject('Service Error');
};
this.servicePostReq = function() {
return aResource.save().$promise.then(success, error);
};
return this;
angular.module('app.service').factory('aService', ['$q', 'aResource', aService]);