我在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
});
这是一个很好的方法吗,还是有更简单的方法?
答案 0 :(得分:94)
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.
}
宣传的版本非常相似:
$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.
});
答案 1 :(得分:42)
忘记使用success
和error
方法。
两种方法都已在角度1.4中弃用。基本上,弃用背后的原因是它们不是可链接友好的,可以这么说。
通过以下示例,我将尝试演示我对success
和error
不是可链接友好的含义。假设我们调用一个返回带有地址的用户对象的API:
用户对象:
{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
返回的那个,因此传递给then
的回调是整个用户对象,也就是前面success
回调的相同输入。
如果我们将两个then
链接起来,那就不那么容易混淆了:
$http.get('/user')
.then(function (user) {
return user.address;
})
.then(function (obj) {
console.log(obj); // -> 'San Francisco'
});
};
答案 2 :(得分:35)
我认为之前的答案是正确的,但这是另一个例子(根据AngularJS Main page只是f.y.i,success()和error()被弃用:
$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');
});
答案 3 :(得分:11)
您在寻找什么类型的粒度?您通常可以使用:
$http.get(url).then(
//success function
function(results) {
//do something w/results.data
},
//error function
function(err) {
//handle error
}
);
我发现&#34;终于&#34;并且&#34;赶上&#34;在链接多个承诺时会更好。
答案 4 :(得分:5)
在Angular $ http的情况下,success()和error()函数会将响应对象解包,因此回调签名就像$ http(...)。success(function(data,status,headers,配置))
对于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(...)将不需要,除非在前一个promise链中抛出新的错误。
答案 5 :(得分:-3)
我这样做就像Bradley Braithwaite在blog:
中所说的那样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;
});
}])
要点:
resolve函数链接到我们控制器中的.then函数,即一切正常,所以我们可以信守承诺并解决它。
拒绝功能链接到我们控制器中的.catch功能,即出现问题,所以我们无法履行承诺和需要 拒绝它。
这是非常稳定和安全的,如果您有其他条件拒绝承诺,您可以随时在成功函数中过滤数据,并以拒绝为原因致电deferred.reject(anotherReason)
。
正如Ryan Vice在评论中所建议的那样,除非你对答案略有提及,否则这可能不会被视为有用。可以这么说。
因为自1.4以来不推荐使用success
和error
,所以最好使用常规的promise方法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
方法(由于抛出,这有点难以测试):
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;
}
虽然有一个中途解决方案(这样你可以避免使用throw
,无论如何你可能需要使用$q
来模拟测试中的promise行为):
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;
}
欢迎任何形式的评论或更正。