[英]Resolving a promise in Angular Service
我們有一個服務,叫它AccountService
,它公開了一個名為getAccounts(customerId)
的方法。
在其實現中,它要做的就是觸發$ http GET請求,並向調用控制器返回承諾,一旦解決,它將把返回的帳戶數組放入控制器范圍內。
在簡化視圖中,所有內容如下所示:
// The service
.factory('AccountService', ['$http', function($http) {
var _getAccounts = function(customerId) {
var request = {
'method': 'GET',
'url': 'http://localhost:8081/accounts/' + customerId
};
return $(request);
};
return {
getAccounts: _getAccounts
};
}]);
// Inside the conntroller
AccountService.getAccounts($scope.customerId)
.then(function(response) {
$scope.accounts = response.data;
});
因此,一旦諾言得以解決,則控制者范圍將被填充帳戶列表。
請注意,我盡可能簡化了上面的代碼,以使您了解我的問題所在,但實際上,它將是處理異常,觀察者進行刷新等的代碼。一切正常。
我的問題是,很多控制器都使用了這個AccountService,並且在所有這些外觀中都使用了承諾解析,這不僅重復了所有這些樣板解析器代碼,而且使單元測試變得復雜,因為我必須成功地對R / test進行測試。每個控制器測試中的異常情況。
所以我的問題是:是否有一種很好的方法來解決服務中的諾言並將響應返回給控制器,而不是諾言?
請注意,我是Angular和JS的初學者,所以如果我的問題太幼稚,請保持謙虛。 我有大量的Java經驗,我的想法似乎像遍地都是Java,但事實並非如此。
預先感謝您的輸入
要回答您的原始問題:
有沒有一種好的方法來解決服務中的承諾並將響應返回給控制器,而不是承諾?
在我看來,不,沒有。 歸結為異步調用的工作方式-您要么傳遞一個回調(該方法不返回任何內容),要么不傳遞一個回調,並且該方法返回一個將被通知的對象(一個Promise)。 可能有一些解決方法,但是我認為沒有比這更好的方法了。
一種部分減少樣板的方法是在服務中使用catch
,然后返回由它返回的承諾 。
考慮以下極其簡化的示例:
angular.module('myApp')
.factory('NetworkRequests', [
function() {
var _getData = function() {
var promise = new Promise((resolve, reject) => {
var a = true,
data = ['a', 'b', 'c'];
if (a) {
resolve(data);
} else {
reject('Rejection reason: ...');
}
});
return promise.catch((error) => {
// Notify some error handling service etc.
console.log(error);
return [];
});
};
return {
getData: _getData
};
}
]);
promise變量將是您的http請求的結果。 您應該在catch函數中返回一些在控制器上下文中有意義的數據(例如,空數組)。 然后,您不必為控制器中的錯誤處理而煩惱:
angular.module('myApp')
.controller('DataController', ['NetworkRequests',
function(NetworkRequests) {
NetworkRequests.getData().then((data) => {
this.data = data;
});
}
]);
同樣,這不能解決完整的問題,但是至少可以將錯誤處理部分封裝在服務中。
您可以這樣設計:一旦$http
完成了數據的獲取,就將其存儲為工廠變量(某種程度上是一個緩存),對於后續的工廠調用,您將檢查緩存中是否包含此類數據。 如果是,則返回緩存數據,否則調用$http
調用。
這是代碼:
.factory('AccountService', ['$http', '$q', function($http, $q) {
var cachedData = null;
var defered = $q.defer(); //create our own defered object
var _getAccounts = function(customerId) {
if (cachedData !== null) {
console.log('get from cachedData')
defered.resolve(cachedData); // resolve it so that the data is passed outside
return defered.promise; //return your own promise if cached data is found
} else {
var request = {
'method': 'GET',
'url': 'mockdata.json'
};
return $http(request).then((response) => { //return a normal $http promise if it is not.
console.log('get from $http');
cachedData = response.data;
return cachedData;
});
}
};
return {
getAccounts: _getAccounts
};
}]);
這是工作中的plnkr 。 您可以打開控制台,然后單擊“ GetData”按鈕。 您將看到它的日志第一次get from $http
,在隨后的調用中,它的日志get from cachedData
。
一種方法是重用對象並用數據填充它。 ngResource使用它。
就像
var data = [];
function getAccounts(customerId) {
var promise = $http(...).then((response) => {
Object.assign(promise.data, response.data)
});
promise.data = [];
return promise;
};
數據可作為$scope.accounts = AccountService.getAccounts(...).data
進行綁定。 明顯的缺點是有大量的卸載內容。
另一種方法是您提到的方法。 它是最常用的。 如果控制器中的WET代碼存在問題,則應通過消除具有類繼承的WET代碼來解決,而不是更改其工作方式。
另一種方法是推薦的方法。 使用路由器和路由/狀態解析器可以消除對異步加載數據的需求。 在解析器中解析的數據作為數組注入到路由模板中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.