[英]Using success/error/finally/catch with Promises in AngularJS
我在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是對語句的抽象,允許我們與異步代碼同步表達自己。 它們代表一次性任務的執行。
它們還提供異常處理,就像普通代碼一樣,您可以從承諾返回,也可以拋出。
您在同步代碼中想要的是:
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
方法。
兩種方法都已在角度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
的回調。
如果我們鏈接2 then
,這將是減少混亂:
$http.get('/user')
.then(function (user) {
return user.address;
})
.then(function (obj) {
console.log(obj); // -> 'San Francisco'
});
};
我認為以前的答案是正確的,但這是另一個例子(根據AngularJS 主頁 ,只是fyi,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');
});
您在尋找什么類型的粒度? 您通常可以通過:
$http.get(url).then(
//success function
function(results) {
//do something w/results.data
},
//error function
function(err) {
//handle error
}
);
我發現鏈接多個承諾時“終於”和“抓住”會更好。
在Angular $ http的情況下,success()和error()函數會將響應對象解包,因此回調簽名就像$ 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;
});
除非在先前的promise鏈中拋出新的錯誤,否則最后的.catch(...)將不需要。
我這樣做就像Bradley Braithwaite在他的博客中建議的那樣:
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;
}
歡迎任何形式的評論或更正。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.