Использование success/error/finally/catch с помощью Promises в AngularJS
Я использую $http
в AngularJs, и я не уверен, как использовать возвращенное обещание и обрабатывать ошибки.
У меня есть этот код:
$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
});
Это хороший способ сделать это, или есть более простой способ?
Ответы
Ответ 1
Promises являются абстракцией над операторами, которые позволяют нам синхронно выражать себя с асинхронным кодом. Они представляют собой выполнение одноразовой задачи.
Они также предоставляют обработку исключений, как и обычный код, вы можете вернуться с обещания или бросить.
Что вы хотите в синхронном коде:
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 better to `return $q.reject(e)` here
}).then(function(res){
// do more stuff
}).catch(function(e){
// handle errors in processing or in error.
});
Ответ 2
Забудьте об использовании методов success
и error
.
Оба метода устарели в angular 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'
});
};
Ответ 3
Я думаю, что предыдущие ответы верны, но вот еще один пример (только fyi, success() и error() устарели в соответствии с 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');
});
Ответ 4
Какой тип детализации вы ищете? Обычно вы можете:
$http.get(url).then(
//success function
function(results) {
//do something w/results.data
},
//error function
function(err) {
//handle error
}
);
Я обнаружил, что "finally" и "catch" лучше при соединении нескольких promises.
Ответ 5
В случае Angular $http функция success() и error() будет отключена отклика, поэтому обратная связь будет похожа на $http (...). success (функция (данные, статус, заголовки, config))
для then(), вы, вероятно, будете иметь дело с необработанным объектом ответа.
например, опубликованные в документе API-интерфейса AngularJS $
$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(...) не понадобится, если в предыдущей цепочке обещаний не возникнет ошибка.
Ответ 6
Я делаю это, как Брэдли Брейтуэйт предлагает в своем blog:
app
.factory('searchService', ['$q', '$http', function($q, $http) {
var service = {};
service.search = function search(query) {
// We make use of Angular $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;
});
}])
Ключевые моменты:
-
Функция разрешения связывается с функцией .then в нашем контроллере, то есть все хорошо, поэтому мы можем сдержать свое обещание и разрешить его.
-
Функция отклонения ссылается на функцию .catch в нашем контроллере, то есть что-то пошло не так, поэтому мы не можем сдержать наше обещание и отвергайте его.
Это довольно стабильно и безопасно, и если у вас есть другие условия, чтобы отклонить обещание, вы всегда можете отфильтровать свои данные в функции успеха и вызвать deferred.reject(anotherReason)
с целью отклонения.
Как предложил Райан Вирд в комментариях, это может быть не так полезно, если вы не будете немного болтать с ответом.
Потому что success
и error
устарели, так как 1.4, возможно, лучше использовать обычные методы обещания then
и catch
и преобразовать ответ в этих методах и вернуть обещание этого преобразованного ответа.
Я показываю тот же пример с обоими подходами и третьим промежуточным подходом:
success
и error
(success
и error
возвращают обещание ответа HTTP, поэтому нам нужна помощь $q
, чтобы вернуть обещание данных):
function search(query) {
// We make use of Angular $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
, чтобы высмеять поведение обещаний в ваших тестах):
function search(query) {
// We make use of Angular $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;
}
Любые комментарии или исправления приветствуются.