在AngularJS中使用Promises的成功/错误/ finally / catch
我在AngularJs中使用$http
,我不确定如何使用返回的promise和处理错误。
我有这个代码:
$http .get(url) .success(function(data) { // Handle data }) .error(function(data, status) { // Handle HTTP error }) .finally(function() { // Execute logic independent of success/error }) .catch(function(error) { // Catch and handle exceptions from success/error/finally functions });
这是一个好办法吗?还是有一个更简单的方法?
Promise是对语句的抽象,允许我们用asynchronous代码同步expression自己。 它们代表一次性任务的执行。
他们也提供exception处理,就像正常的代码一样,你可以从promise中返回或者抛出。
你在同步代码中想要的是:
try{ try{ var res = $http.getSync("url"); res = someProcessingOf(res); } catch (e) { console.log("Got an error!",e); throw e; // rethrow to not marked as handled } // do more stuff with res } catch (e){ // handle errors in processing or in error. }
promisified版本是非常相似的:
$http.get("url"). then(someProcessingOf). catch(function(e){ console.log("got an error in initial processing",e); throw e; // rethrow to not marked as handled, // in $q it's better to `return $q.reject(e)` here }).then(function(res){ // do more stuff }).catch(function(e){ // handle errors in processing or in error. });
忘记使用success
和error
方法。
这两个方法在angular度1.4都被弃用了。 基本上,贬低的原因是它们不是可链接的 ,可以这么说。
通过下面的例子,我将试图certificate我的意思是success
和error
是不可链接的 。 假设我们调用一个API来返回一个地址为user的对象:
用户对象:
{name: 'Igor', address: 'San Francisco'}
调用API:
$http.get('/user') .success(function (user) { return user.address; <--- }) | // you might expect that 'obj' is equal to the .then(function (obj) { ------ // address of the user, but it is NOT console.log(obj); // -> {name: 'Igor', address: 'San Francisco'} }); };
发生了什么?
因为success
和error
返回原来的承诺 ,即由$http.get
返回的$http.get
,那么传递给该对象的callback的对象就是整个用户对象,也就是说,与前一个success
callback相同的input。
如果我们连接了两个, then
这个问题就不会那么混乱了:
$http.get('/user') .then(function (user) { return user.address; }) .then(function (obj) { console.log(obj); // -> 'San Francisco' }); };
我认为以前的答案是正确的,但这里是另一个例子(只是一个fyi,成功()和错误()是根据AngularJS 主页面弃用:
$http .get('http://someendpoint/maybe/returns/JSON') .then(function(response) { return response.data; }).catch(function(e) { console.log('Error: ', e); throw e; }).finally(function() { console.log('This finally block'); });
你在寻找什么types的粒度? 你通常可以通过:
$http.get(url).then( //success function function(results) { //do something w/results.data }, //error function function(err) { //handle error } );
我发现,链接多个承诺时,“终于”和“赶上”会更好。
在Angular $ http的情况下,success()和error()函数会解开响应对象,所以callback签名就像$ http(…)。success(function(data,status,headers,config))
对于then(),你可能会处理原始响应对象。 比如发布在AngularJS $ http API文档中
$http({ url: $scope.url, method: $scope.method, cache: $templateCache }) .success(function(data, status) { $scope.status = status; $scope.data = data; }) .error(function(data, status) { $scope.data = data || 'Request failed'; $scope.status = status; });
除非在之前的承诺链中出现新的错误,否则最后的.catch(…)将不需要。
我喜欢布拉德利布雷斯韦特在他的博客中build议:
app .factory('searchService', ['$q', '$http', function($q, $http) { var service = {}; service.search = function search(query) { // We make use of Angular's $q library to create the deferred instance var deferred = $q.defer(); $http .get('http://localhost/v1?=q' + query) .success(function(data) { // The promise is resolved once the HTTP call is successful. deferred.resolve(data); }) .error(function(reason) { // The promise is rejected if there is an error with the HTTP call. deferred.reject(reason); }); // The promise is returned to the caller return deferred.promise; }; return service; }]) .controller('SearchController', ['$scope', 'searchService', function($scope, searchService) { // The search service returns a promise API searchService .search($scope.query) .then(function(data) { // This is set when the promise is resolved. $scope.results = data; }) .catch(function(reason) { // This is set in the event of an error. $scope.error = 'There has been an error: ' + reason; }); }])
关键点:
parsing函数链接到我们控制器中的.then函数,即一切正常,所以我们可以信守诺言并加以解决。
拒绝函数链接到我们控制器中的.catch函数,即出错了,所以我们不能遵守我们的承诺,并且需要拒绝它。
这是相当稳定和安全的,如果你有其他条件拒绝承诺,你总是可以过滤你的数据在成功函数和调用deferred.reject(anotherReason)
的原因拒绝。
正如Ryan Vice在评论中所build议的那样 ,这可能不会被认为是有用的,除非你在回应中摆弄一下,可以这么说。
因为success
和error
从1.4开始被弃用,所以最好使用常规的承诺方法, then
在这些方法中catch
和转换响应,并返回转换响应的承诺。
我用两种方法和第三种方法展示了同样的例子:
success
和error
方法( success
和error
返回一个HTTP响应的承诺,所以我们需要$q
的帮助来返回数据的承诺):
function search(query) { // We make use of Angular's $q library to create the deferred instance var deferred = $q.defer(); $http.get('http://localhost/v1?=q' + query) .success(function(data,status) { // The promise is resolved once the HTTP call is successful. deferred.resolve(data); }) .error(function(reason,status) { // The promise is rejected if there is an error with the HTTP call. if(reason.error){ deferred.reject({text:reason.error, status:status}); }else{ //if we don't get any answers the proxy/api will probably be down deferred.reject({text:'whatever', status:500}); } }); // The promise is returned to the caller return deferred.promise; };
then
和catch
方法(这是一个更难以testing,因为抛出):
function search(query) { var promise=$http.get('http://localhost/v1?=q' + query) .then(function (response) { // The promise is resolved once the HTTP call is successful. return response.data; },function(reason) { // The promise is rejected if there is an error with the HTTP call. if(reason.statusText){ throw reason; }else{ //if we don't get any answers the proxy/api will probably be down throw {statusText:'Call error', status:500}; } }); return promise; }
虽然有一个中途的解决scheme(这样你可以避免throw
,无论如何,你可能需要使用$q
来模拟testing中的承诺行为):
function search(query) { // We make use of Angular's $q library to create the deferred instance var deferred = $q.defer(); $http.get('http://localhost/v1?=q' + query) .then(function (response) { // The promise is resolved once the HTTP call is successful. deferred.resolve(response.data); },function(reason) { // The promise is rejected if there is an error with the HTTP call. if(reason.statusText){ deferred.reject(reason); }else{ //if we don't get any answers the proxy/api will probably be down deferred.reject({statusText:'Call error', status:500}); } }); // The promise is returned to the caller return deferred.promise; }
欢迎任何forms的评论或更正。