我正在尝试找到一种最佳实践,以便在返回第一个函数时多次调用$ resource。
考虑以下架构:我们有一个作者数据库,它有书籍,有多个标签(sf,惊悚片,恐怖片......)。
angular.module('myApp',[ngResource])
.controller('myCtrl',['$scope', function($scope){
$scope.results = [];
apiService.Authors.getAll().$promise //return array of authors
.then(function(authors){
$scope.results.push(authors);
angular.forEach(authors,function(akey,author){
apiService.BooksBy.getAll({authorID:author.id}).$promise //return array of books
.then(function(books){
$scope.results[akey].books = [];
$scope.results[akey].books.push(books);
angular.forEach(books,function(bkey,book){
apiService.Tags.getAll({bookID:book.id}).$promise //return array of tags
.then(function(tags){
$scope.results[akey].book[bkey].tags = [];
$scope.results[akey].book[bkey].tags.push(tags);
});
});
});
});
});
}]);
这是进行多个嵌套调用的唯一方法吗?
我正在考虑更多扁平并且更具可读性的东西,比如带有链式承诺的解决方法。
任何想法都会受到欢迎,因为我无法找到更好的方法。
问候!
答案 0 :(得分:0)
您可以使用$ q拨打多个电话。它是调用多个调用的最佳方式,如果所有调用都是return promises,则结束调用
如果您根据先前结果的呼叫呼叫多个呼叫,那么这是执行此操作的最佳方式。
static void Main(string[] args)
{
int max, i, count;
i = 0; // this is used to keep trck of how many primes have been added to the array
count = 0; // this is used to test each number
Console.WriteLine("This will work out the first x prime numbers with x being the number of prime numbers you want");
Console.WriteLine("Enter the number of prime numbers you want.");
max = Convert.ToInt32(Console.ReadLine());
int[] primes = new int[max];
while (i <= max)
{
while (count <= 9999)
{
if (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 ) // tests if count number is a prime
{
if (count == 2 || count == 3 ||count == 5 ||count == 7 ) // ensures 2,3,5,7 are added to primes if neccesarry
{
primes[count] = count; //add to array
i++; // increments the count on the number of prime numbers
}
count ++; // increments the count
break;
}
else
{
primes[count] = count;
i++;
count ++;
}
}
}
Console.WriteLine("The first {0} prime numbers are ... ", max);
foreach(var item in primes)
{
Console.Write(item.ToString() + ", ");
}
}
答案 1 :(得分:0)
这是一个可能的解决方案:如果你使用$q.all
,但是对于你推送到数组的每个承诺,你添加一个'sub' - .then
,你可以包装每个人的结果api调用并将其与您需要由下一个.then
- 处理程序使用的密钥(或其他任何内容)一起传递。
我试图通过一些更改,非常密切地反映原始代码示例:
.then
- 处理程序,以更清楚地证明我们已经将链条弄平了angular.extend
更新范围上的json结构,该结构显示在<pre>
标记内。您的原始代码示例正在使用数组执行某些操作,但我不确定它是否会按预期工作 - 我使用angular.extend
意味着接近我认为您的目的。applyBooksGetTags
函数中,我们尝试同时传递akey
和bkey
以及结果。但是,akey
实际上来自之前的结果 - 以result.akey
访问。这存在于我们用于编译promise数组的angular.forEach
循环之外的范围内 - 当forEach
函数执行时,result.akey
将被外部{{1}更改循环。出于这个原因,我在一个自动执行的函数中封装了对forEach的调用 - 一个闭包,以确保在每个事情发生时保持for
的值。result.akey
次调用可能已经交换了(值,键)参数的顺序 - 因此已在下面的代码段中进行了交换angular.forEach
个评论...这主要是因为代码片段'整理'功能使代码有点难以理解;遗憾!
} //end blah blah
(function() {
"use strict";
angular.module('myApp', [])
.controller('myCtrl', ['$scope', '$q', 'apiService', MyCtrl])
.service('apiService', ['$timeout', mockApiService]);
function MyCtrl($scope, $q, apiService) {
$scope.results = {};
apiService.Authors.getAll().$promise
.then(applyAuthorsGetBooks)
.then(applyBooksGetTags)
.then(applyTags);
function applyAuthorsGetBooks(authors) {
var promises = [];
angular.extend($scope.results, authors);
angular.forEach(authors, function(author, akey) {
promises.push(apiService.BooksBy.getAll({
authorID: author.id
}).$promise
.then(function(books) {
return $q.when({ // < MAGIC HERE: return the books, but also the aKey
books: books,
akey: akey
}); //end return
}) //end then
); //end push
}); //end foreach
return $q.all(promises);
} // end authorsGetBooks
function applyBooksGetTags(results) {
var promises = [];
for (var i = 0; i < results.length; i++) {
var result = results[i];
$scope.results[result.akey].books = angular.extend({}, result.books);
(function(akey) { //anon func to wrap the current value of akey in a closure, so when inner loop accesses it hasn't been changed by outer loop
angular.forEach(result.books, function(book, bkey) {
promises.push(apiService.Tags.getAll({
bookID: book.id
}).$promise
.then(function(tags) {
return $q.when({ // < MAGIC HERE, again: return the tags, but also the bkey and akey
tags: tags,
akey: akey,
bkey: bkey
}); //end return
}) //end then
); //end push
}); //end foreach
})(result.akey) //pass our current akey value to our anon func
} //end for
return $q.all(promises);
} //end booksGetTags
function applyTags(results) {
for (var i = 0; i < results.length; i++) {
var result = results[i];
$scope.results[result.akey].books[result.bkey].tags = angular.extend({}, result.tags);
} //end for
}
} //end MyCtrl
function mockApiService($timeout) {
function _simulateResource(data) {
return {
$promise: $timeout(function timeoutHandler() {
return data;
}, 1000) //end $timeout
}; //end return
} //end _simulateResource()
return {
Authors: {
getAll: function authorsGetAll() {
return _simulateResource({
Author1: {
id: 'Author 1'
},
Author2: {
id: 'Author 2'
}
}); //end return
} //end getAll
}, //end Authors
BooksBy: {
getAll: function booksByGetAll(params) {
var authorId = params.authorID;
return _simulateResource({
Book1: {
id: 'Book 1 by ' + authorId
},
Book2: {
id: 'Book 2 by ' + authorId
}
}); //end return
} //end getAll
}, //end BooksBy
Tags: {
getAll: function tagsGetAll(params) {
var bookId = params.bookID;
return _simulateResource({
Rom: {
id: 'Rom'
},
Zom: {
id: 'Zom'
},
Com: {
id: 'Com'
}
}); //end return
} //end getAll
} //end Tags
}; //end return
} // end MockService API
})();