在AngularJS中的嵌套异步调用中交换数据
我是AngularJS的新手,我面临着一个有趣的问题: 我创建了一个Angular factory服务,作为我正在调用的REST服务的服务代理。 我的服务代理如下所示:在AngularJS中的嵌套异步调用中交换数据,angularjs,rest,tags,promise,Angularjs,Rest,Tags,Promise,我是AngularJS的新手,我面临着一个有趣的问题: 我创建了一个Angular factory服务,作为我正在调用的REST服务的服务代理。 我的服务代理如下所示: angular.module('myApp').factory('myService', ['$http', function($http) { var baseAddr = "http://myservice.com"; var token = "secure_identifier"; var My
angular.module('myApp').factory('myService', ['$http', function($http) {
var baseAddr = "http://myservice.com";
var token = "secure_identifier";
var MyService = {
doRequest: function(method, path, token, postData) {
return $http({method: method, url: baseAddr+path, headers: {....}, data:postData });
}
}
return {
GetGroupUsers: function( id)
{
return MyService.doRequest('GET', '/api/groupusers/'+id+'.json', token, null);
},
GetUser: function( id)
{
return MyService.doRequest('GET', '/api/users/'+id+'.json', token, null);
}
}
}]);
因此,GetGroupUsers返回给定组中的userID-s数组,GetUser返回
指定的成员(例如电子邮件地址、全名、用户名、出生日期)。
我想要的是查询一个组(获取该组中的userid-s)并将用户的名称附加到数组项
在GetUser(userid)方法的帮助下。
我有一个控制器,在其中我通过我的代理服务查询这个服务。以下是控制器的相关部分:
//...
MyService.GetGroupUsers(GroupId).then(function(userlist)
{
//userlist is an array of a complex object that consists of userId-s and groupId-s
//Suppose that it looks like this:
// [ {uid: 1, groupId: 1}, {uid: 2, groupId: 1}, {uid: 3, groupId: 1},...,.. ]
$scope.groups = userlist.data;
//but i need to attach for every item in the array the name of the selected user
// [ {uid: 1, groupId: 1,username: 'Alga Rithem'}, {uid: 2, groupId: 1, username:'Anna Nimmity'}, {uid: 3, groupId: 1, username:'Anna Conda'},...,.. ]
//So I iterate over the userlist
for (var i = 0; i < userlist.data.length; i++)
{
MyService.GetUser(userlist.data[i].uid).
then(function(user)
{
//And here is the problem I'm facing with:
//The value of variable "i" becomes obsolate, because GetUser call is async to the for-loop
// when the "then" "callback" executes, the loop may has been finished already!
//So I dont really know, where to put the value I've just received
//I need that value of i, what it was when i called the service!
$scope.groups[i].name = user.data.name; //So this is WRONG!
});
}
});
//...
现在我可以在我的控制器中检索有效的、过去的I值:
//...
MyService.GetGroupUsers(GroupId).then(function(userlist)
{
//userlist is an array of a complex object that consists of userId-s and groupId-s
//Suppose that it looks like this:
// [ {uid: 1, groupId: 1}, {uid: 2, groupId: 1}, {uid: 3, groupId: 1},...,.. ]
$scope.groups = userlist.data;
//but i need to attach for every item in the array the name of the selected user
// [ {uid: 1, groupId: 1,username: 'Alga Rithem'}, {uid: 2, groupId: 1, username:'Anna Nimmity'}, {uid: 3, groupId: 1, username:'Anna Conda'},...,.. ]
//So I iterate over the userlist
for (var i = 0; i < userlist.data.length; i++)
{
MyService.GetUser(userlist.data[i].uid).
then(function(user)
{
//And here is the problem I'm facing with:
//The value of variable "i" becomes obsolate, because GetUser call is async to the for-loop
// when the "then" "callback" executes, the loop may has been finished already!
//So I dont really know, where to put the value I've just received
//I need that value of i, what it was when i called the service!
$scope.groups[i].name = user.data.name; //So this is WRONG!
});
}
});
//...
修改的控制器代码:
//...
MyService.GetGroupUsers(GroupId).then(function(userlist)
{
$scope.groups = userlist.data;
for (var i = 0; i < userlist.data.length; i++)
{
MyService.GetUser(adat.data[i].uid).
then(function(user)
{
$scope.groups[parseInt(user.config.tag)].name = user.data.name; //This Works fine!
});
}
});
/。。。
GetGroupUsers(GroupId).then(函数(userlist)
{
$scope.groups=userlist.data;
对于(var i=0;i
我的问题是:这个解决方案在技术上正确吗?解决此类问题的最佳做法是什么?
AngularJS有这样的工具吗
ps:在这种情况下,修改REST服务API以返回用户名并不是一个解决方案
提前感谢您可以使用
.forEach
循环,而不是关闭i
的for
循环:
userlist.data.forEach(function(user, i){
MyService.GetUser(user.uid).
then(function(user)
{
$scope.groups[i].name = user.data.name; //So this is WRONG!
});
}
或者,您可以使用.map
创建映射,并使用$q.all
一次性进行所有更新:
$q.all(userlist.data.map(function(user){
return MyService.GetUser(user.uid))
}).then(function(users){
// assign to scope, users is an array here and you can use indices
});
虽然真正实用的解决方案不是为
n
用户调用n
,而是创建一种方法,在服务器上接受多个UID,并同时为他们获取所有数据,因为它不会进行n
往返和http请求,因此系统负载更少,执行更快。如果您的API是REST,考虑使用<代码> $Reals,这使得事情变得简单多了。另外,能否准确显示所有信息GetUser
返回值?假设GetUser返回一个JSON对象,如下所示:“{”id“:9,“email”:”myemail@mycompany.com“,”用户名“:”我的昵称“}”$resource如何让我更轻松?无论如何,我需要在某个地方“连接”这些对象。是吗?谢谢你的回答。您的第一个示例不会减慢网页的加载时间吗?我的意思是forEach使服务调用同步,所以控制器将等待forEach完成,这可能非常耗时。在您的第二个解决方案中,我如何检索标记?你能给我链接一篇关于这种数据映射的文章吗?我真的不明白这件事。谢谢。@bkotyik它正在做。forEach
而不是for
并不会神奇地使调用同步,它只是同步地进行调用(注意区别,调用仍然是异步进行的)。在第二个示例中,您可以通过将users[i]与$scope.groups[i]
匹配来检索索引,因为您拥有整个数组。你的解决方案确实改变了后端API。好的,明白了。谢谢大家!+1个问题如果您不介意的话:如果这些服务调用中的任何一个在序列中失败,我如何知道哪一个用户查询失败了?您可以将.catch
处理程序附加到承诺中-请参阅