在 AngularJS 1.4 中的另一个 return 之后多次调用 $resource
Make multiple calls to $resource after the return of another one in AngularJS 1.4
我目前正在尝试寻找一种最佳实践,以便在第一个 return 的函数中对 $resource 进行多次调用。
考虑以下模式:我们有一个作者数据库,其中有书籍,有多个标签(科幻、惊悚、恐怖……)。
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);
});
});
});
});
});
}]);
这是进行多次嵌套调用的唯一方法吗?
我在想一些更扁平化和更具可读性的东西,比如链式承诺的解决方法。
欢迎提出任何想法,因为我找不到更好的方法。
此致!
您可以使用$q 拨打多个电话。它是调用多个调用的最佳方式,如果所有调用都是 return promises
,它就会结束
如果您根据之前的结果调用多个调用,那么这是执行此操作的最佳方法。
function httpCall()
{
var promises=[];
promises.push(yourhttpCall1())
return $q.all(promises);
}
$q.all([httpCall]).then(function(result){});
这是一个可能的解决方案:如果你使用 $q.all
,但是对于你推送到数组的每个承诺,你添加一点 'sub'-.then
,你可以包装结果每个人 api 调用并将其与您需要的密钥(或其他任何内容)一起传递给下一个 .then
-处理程序。
我已尝试相当接近地反映您的原始代码示例,并进行了一些更改:
- 我创建了一个小的 mockApiService,但为了简单起见,我捏造了几个调用
- 我已经用命名函数替换了内联
.then
-处理程序,以更清楚地证明我们已经展平链
- 我正在使用
angular.extend
更新作用域上的 json 结构,该结构显示在 <pre>
标记内。您的原始代码示例是用数组做一些事情,但我不确定它是否会按预期工作 - 我使用 angular.extend
是为了近似我所想的。
- 在我的
applyBooksGetTags
函数中,我们试图将 akey
和 bkey
与结果一起传递。然而,akey
实际上是从之前的结果中获得的——作为 result.akey
访问。这存在于我们用来编译 promise 数组的 angular.forEach
循环之外的范围内——当 forEach
函数执行时,result.akey
将被外部 [=27] 更改=] 循环。出于这个原因,我将对 forEach 的调用包装在一个自执行函数中 - 一个闭包,以确保 result.akey
的值在 forEach 执行其操作时得到维护。
- 原始示例中的
angular.forEach
调用可能交换了(值,键)参数的顺序 - 因此在下面的代码片段中交换回来了
- 有很多
} //end blah blah
评论...这主要是因为代码片段编辑器 'tidy' 功能使代码难以遵循;抱歉!
(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
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
<pre ng-controller='myCtrl'>{{results|json}}</pre>
</div>
我目前正在尝试寻找一种最佳实践,以便在第一个 return 的函数中对 $resource 进行多次调用。
考虑以下模式:我们有一个作者数据库,其中有书籍,有多个标签(科幻、惊悚、恐怖……)。
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);
});
});
});
});
});
}]);
这是进行多次嵌套调用的唯一方法吗?
我在想一些更扁平化和更具可读性的东西,比如链式承诺的解决方法。
欢迎提出任何想法,因为我找不到更好的方法。
此致!
您可以使用$q 拨打多个电话。它是调用多个调用的最佳方式,如果所有调用都是 return promises
,它就会结束如果您根据之前的结果调用多个调用,那么这是执行此操作的最佳方法。
function httpCall()
{
var promises=[];
promises.push(yourhttpCall1())
return $q.all(promises);
}
$q.all([httpCall]).then(function(result){});
这是一个可能的解决方案:如果你使用 $q.all
,但是对于你推送到数组的每个承诺,你添加一点 'sub'-.then
,你可以包装结果每个人 api 调用并将其与您需要的密钥(或其他任何内容)一起传递给下一个 .then
-处理程序。
我已尝试相当接近地反映您的原始代码示例,并进行了一些更改:
- 我创建了一个小的 mockApiService,但为了简单起见,我捏造了几个调用
- 我已经用命名函数替换了内联
.then
-处理程序,以更清楚地证明我们已经展平链 - 我正在使用
angular.extend
更新作用域上的 json 结构,该结构显示在<pre>
标记内。您的原始代码示例是用数组做一些事情,但我不确定它是否会按预期工作 - 我使用angular.extend
是为了近似我所想的。 - 在我的
applyBooksGetTags
函数中,我们试图将akey
和bkey
与结果一起传递。然而,akey
实际上是从之前的结果中获得的——作为result.akey
访问。这存在于我们用来编译 promise 数组的angular.forEach
循环之外的范围内——当forEach
函数执行时,result.akey
将被外部 [=27] 更改=] 循环。出于这个原因,我将对 forEach 的调用包装在一个自执行函数中 - 一个闭包,以确保result.akey
的值在 forEach 执行其操作时得到维护。 - 原始示例中的
angular.forEach
调用可能交换了(值,键)参数的顺序 - 因此在下面的代码片段中交换回来了 - 有很多
} //end blah blah
评论...这主要是因为代码片段编辑器 'tidy' 功能使代码难以遵循;抱歉!
(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
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<div ng-app="myApp">
<pre ng-controller='myCtrl'>{{results|json}}</pre>
</div>