Angular 在服务内部移动成功递归回调
Angular move success recursive callback inside service
我有一项 returns $http 承诺的服务。这工作正常,但我需要进行递归调用以防列表 returns 超过 100 个项目。同样,这工作正常,但我要为每个控制器重复一遍。我无法将递归卸载到服务并仍然得到最终结果。也许 $q
能帮上忙?
// service
function List ($http) {
var headers = {'Accept': 'application/json;odata=verbose'}
, listService = {
getByName: function (listName) {
return $http({
method: 'GET'
, url: '/_api/web/lists/getByTitle(\'' + listName + '\')/items'
, headers: headers
});
}
, getByUrl: function (url) {
return $http({
method: 'GET'
, url: url
, headers: headers
})
}
};
return listService;
}
// controller
function Calendar ($scope, List) {
$scope.events = [];
List.getByName('Calendar').success(function (response) {
$scope.events = response.d.results;
if (response.d.__next) {
List.getByUrl(response.d.__next).success(recursiveSuccess);
}
});
function recursiveSuccess (response) {
$scope.events = $scope.events.concat(response.d.results);
if (response.d.__next) {
List.getByUrl(response.d.__next).success(recursiveSuccess);
}
}
}
由于每次调用都会为您提供下一个端点的 URL,因此 必须 在连续的 HTTP 调用中完成。就承诺而言,它在概念上会像这样完成:
return firstCall.then(function(data){
return secondCall(data);
})
// another .then
// another .then
.then(function(data){
return lastCall(data);
});
这里的每个 NCall
都是一个函数,它获取上一个调用的数据和 returns 对下一个聚合数据的承诺,以及 lastCall
returns 最终聚合数据.
如果将其转换为递归函数,它将如下所示:
function getItemsFrom(url, items){
return $http.get(url).then(function(response){
items = items.concat(response.data.items);
if (response.data.next){
return getItemsFrom(response.data.next, items);
} else {
return items;
}
});
}
数据为:
{
"next": "url/to/data2.json",
"items": [1, 2, 3]
}
唯一剩下的就是最初的调用:
.factory("fooSvc", function($http){
function getItemsFrom(url, items){
// as above
}
return {
getItems: function(){
return getItemsFrom("url/to/data1.json", []);
}
};
});
是的,我遇到过类似的问题,我不得不在服务的一个方法中进行多次调用,使用 $q
解决了这个问题。一旦你学会了如何使用它,它会非常强大。
在您的服务方式中:
function promiseYoullCallMeWhenYoureComplete () {
var deferred = $q.defer();
var events = [];
startMyQuery();
return deferred.promise;
////////////
function startMyQuery () {
List.getByName('Calendar').then(success, error);
}
function success (response) {
// perform success actions
events = angular.extend(events, response.data.d.results);
// run next query or exit if complete
if (response.data.next) {
return startMyQuery();
}
// no more queries, so exit and return my combined events array
return deferred.resolve(events);
}
function error (response) {
return deferred.reject(response);
}
}
然后在你的控制器中,像这样:
List.promiseYoullCallMeWhenYoureComplete().then(success, error);
///////////
function success (events) {
$scope.events = events;
}
function error (response) {
console.error("Error:", response);
}
通过这种方式,您的服务可以进行 $http 查询,直到奶牛回家,但您的控制器只会收到一个单一的响应来处理(成功,其中包含您通过 resolve(...)
方法,或错误。因此您的控制器非常干净,因为您可以将所有逻辑移至服务中。
我有一项 returns $http 承诺的服务。这工作正常,但我需要进行递归调用以防列表 returns 超过 100 个项目。同样,这工作正常,但我要为每个控制器重复一遍。我无法将递归卸载到服务并仍然得到最终结果。也许 $q
能帮上忙?
// service
function List ($http) {
var headers = {'Accept': 'application/json;odata=verbose'}
, listService = {
getByName: function (listName) {
return $http({
method: 'GET'
, url: '/_api/web/lists/getByTitle(\'' + listName + '\')/items'
, headers: headers
});
}
, getByUrl: function (url) {
return $http({
method: 'GET'
, url: url
, headers: headers
})
}
};
return listService;
}
// controller
function Calendar ($scope, List) {
$scope.events = [];
List.getByName('Calendar').success(function (response) {
$scope.events = response.d.results;
if (response.d.__next) {
List.getByUrl(response.d.__next).success(recursiveSuccess);
}
});
function recursiveSuccess (response) {
$scope.events = $scope.events.concat(response.d.results);
if (response.d.__next) {
List.getByUrl(response.d.__next).success(recursiveSuccess);
}
}
}
由于每次调用都会为您提供下一个端点的 URL,因此 必须 在连续的 HTTP 调用中完成。就承诺而言,它在概念上会像这样完成:
return firstCall.then(function(data){
return secondCall(data);
})
// another .then
// another .then
.then(function(data){
return lastCall(data);
});
这里的每个 NCall
都是一个函数,它获取上一个调用的数据和 returns 对下一个聚合数据的承诺,以及 lastCall
returns 最终聚合数据.
如果将其转换为递归函数,它将如下所示:
function getItemsFrom(url, items){
return $http.get(url).then(function(response){
items = items.concat(response.data.items);
if (response.data.next){
return getItemsFrom(response.data.next, items);
} else {
return items;
}
});
}
数据为:
{
"next": "url/to/data2.json",
"items": [1, 2, 3]
}
唯一剩下的就是最初的调用:
.factory("fooSvc", function($http){
function getItemsFrom(url, items){
// as above
}
return {
getItems: function(){
return getItemsFrom("url/to/data1.json", []);
}
};
});
是的,我遇到过类似的问题,我不得不在服务的一个方法中进行多次调用,使用 $q
解决了这个问题。一旦你学会了如何使用它,它会非常强大。
在您的服务方式中:
function promiseYoullCallMeWhenYoureComplete () {
var deferred = $q.defer();
var events = [];
startMyQuery();
return deferred.promise;
////////////
function startMyQuery () {
List.getByName('Calendar').then(success, error);
}
function success (response) {
// perform success actions
events = angular.extend(events, response.data.d.results);
// run next query or exit if complete
if (response.data.next) {
return startMyQuery();
}
// no more queries, so exit and return my combined events array
return deferred.resolve(events);
}
function error (response) {
return deferred.reject(response);
}
}
然后在你的控制器中,像这样:
List.promiseYoullCallMeWhenYoureComplete().then(success, error);
///////////
function success (events) {
$scope.events = events;
}
function error (response) {
console.error("Error:", response);
}
通过这种方式,您的服务可以进行 $http 查询,直到奶牛回家,但您的控制器只会收到一个单一的响应来处理(成功,其中包含您通过 resolve(...)
方法,或错误。因此您的控制器非常干净,因为您可以将所有逻辑移至服务中。