Использование success / error / finally / catch с обещаниями в 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
});
это хороший способ сделать это, или есть более простой способ?
6 ответов:
обещания-это абстракция над утверждениями, которые позволяют нам выражать себя синхронно с асинхронным кодом. Они представляют собой выполнение одноразовой задачи.
Они также обеспечивают обработку исключений, как и обычный код, вы можете вернуться из обещания или вы можете бросить.
что вы хотите в синхронном коде:
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. });
забудьте об использовании
success
иerror
метод.оба метода устарели в angular 1.4. В принципе, причина устаревания заключается в том, что они не chainable-friendly, так сказать.
в следующем примере я попытаюсь продемонстрировать, что я имею в виду
success
иerror
не chainable-friendly. Предположим, мы вызываем 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' }); };
Я думаю, что предыдущие ответы верны, но вот еще один пример (просто f.y. i, 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'); });
какой тип детализации вы ищете? Обычно вы можете обойтись:
$http.get(url).then( //success function function(results) { //do something w/results.data }, //error function function(err) { //handle error } );
Я обнаружил, что "наконец" и "поймать" лучше при цепочке нескольких обещаний.
в случае Angular $http функция success() и error() будет разворачивать объект ответа, поэтому подпись обратного вызова будет похожа на $http(...).успех (функция (данные, статус, заголовки, конфигурация))
для then (), вы, вероятно, будете иметь дело с необработанным объектом ответа. например, опубликовано в AngularJS $http API document
$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; });
последние .поймать.(..) не понадобится, если нет новой ошибки выбросить в предыдущей цепочке обещаний.
я делаю это так, как предлагает Брэдли Брейтуэйт в своем блог:
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 ссылается на.затем функционируйте в нашем контроллере, т. е. все хорошо, поэтому мы можем сдержать свое обещание и решить его.
функция отклонения ссылки на .функция catch в нашем контроллере, т. е. что-то пошло не так, поэтому мы не можем сдержать свое обещание и должны отклонять оно.
это довольно стабильно и безопасно, и если у вас есть другие условия, чтобы отклонить обещание, вы всегда можете отфильтровать свои данные в функции успеха и вызвать
deferred.reject(anotherReason)
С причиной отказа.как Райан вице предложил в комментариях, это не может рассматриваться как полезный, если вы возиться немного с ответом, так сказать.
, потому что
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
подход (это немного сложнее проверить, из-за броска):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'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; }
любые комментарии или исправления приветствуются.