链接 ngResource $promise 成功和错误
Posted
技术标签:
【中文标题】链接 ngResource $promise 成功和错误【英文标题】:chaining ngResource $promise success and errors 【发布时间】:2015-05-07 11:34:57 【问题描述】:我想知道是否可以在多个级别上处理 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
我如何链接承诺,这样我就不必为每个使用服务的控制器添加服务中处理的代码?
【问题讨论】:
【参考方案1】:添加对$q
的依赖并使用$q.reject
来控制执行...
在您的示例中,您需要在 aService.error
方法中使用 $q.reject
如上所述here in the $q docs
reject(reason);
创建一个以指定原因被拒绝的承诺。这个 api 应该用于在一系列 Promise 中转发拒绝。如果您正在处理 Promise 链中的最后一个 Promise,则无需担心。
当将 deferreds/promises 与熟悉的 try/catch/throw 行为进行比较时,可以将拒绝视为 javascript 中的 throw 关键字。这也意味着,如果您通过 promise 错误回调“捕获”错误,并且希望将错误转发到从当前 promise 派生的 promise,则必须通过返回通过拒绝构造的拒绝来“重新抛出”错误。
【讨论】:
【参考方案2】:为了正确链接承诺,成功和错误处理程序都应该返回一些值。返回值会自动包装在一个新的 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]);
【讨论】:
虽然我同意你的大部分回答,但我对为什么 aService.success 方法不使用 $q.resolve() 而 aService.error 使用 $q.reject() 感到困惑。 这仍然行不通。原因是因为aResource.save().$promise.then(success, error)
既是thenable 又包含一个错误处理程序。无论是否有错误,任何链接到那里的 .then 语句都将运行。 this Plunkr 中的示例(打开控制台查看输出)。【参考方案3】:
问题在于您的服务。改变这个:
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)
,它返回了一个包含错误处理程序的新承诺。稍后,在您的控制器中,您可以像这样添加到链中。
aService.servicePostReq().then(success, error);
如果将其展开,此时完整的 Promise 链看起来:
return aResource.save().$promise
.then(successFnFromService, errorFnFromService)
.then(successFnFromController, errorFnFromController);
由于您使用errorFnFromService
捕获了来自aResource.save()
的错误,因此此时承诺链基本上是“干净的”,它将继续下一个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
以查看它对输出的影响。
【讨论】:
以上是关于链接 ngResource $promise 成功和错误的主要内容,如果未能解决你的问题,请参考以下文章
[AngularJS] AngularJS系列 进阶篇之promise
与 ngResource 相比,使用 Restangular 有啥优势?
我如何在 angularjs 中使用 Restful。我使用了 ngResource 但它不起作用。如果我使用 ngResource,js 文件 nt 正在执行