angular 链接数组的承诺
angular chaining arrays of promises
我正在建立一个基于音乐曲目数据库的网站。数据库如下:
- music table 包含 musicid 和标题
- musicrights table 包含 musicid 和 memberid
- members table 包含 memberid 和 memberinfo.
我正在尝试在我的 database
服务中构建一个 objects 数组,其中每个条目代表一个包含其权利人的曲目(包含关于一个权利人的信息,但不包含他的名字)及其会员信息(包含姓名等)。后台是sailsjs,代码如下:
angular.module("myapp").service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberid: rightHolder.memberid
})).then(function (res) {
rightHolder.member = res.data[0];
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/musicrights?where=" + JSON.stringify({
musicid: doc.musicid
})).then(function(res) {
// array of promises :
// each rightholder of a document has to solve member info
var rightHolders = [];
for (var i in res.data) {
var rightHolder = {
member: res.data[i].memberid,
type: res.data[i].membertype,
rights: res.data[i].memberrights
};
rightHolders.push(getHolderMember(rightHolder));
}
return ($q.all(rightHolders));
}).then(function(rightHolders) {
// expected array of one or two rightholders,
// enriched with member information
// actually returns array of one or two arrays of 30 members
// without rightholder info
console.log(rightHolders);
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
// array of 30 promises :
// each one of 30 documents has to resolve its rightholders
var documents = [];
for (var i in res.data) {
documents.push(getRightHolders(res.data[i]));
}
return ($q.all(documents));
}));
}
return (database);
}]);
第一组 promise 似乎按预期工作,但 getRightHolders 中的第二组不是。奇怪的是,这个函数 returns 一个数组,其中包含一个或两个 promises,它们是 rightHolders waiting for their memberinfo。但是在我 console.log 响应的回调中,我得到一个或两个数组(根据推送的承诺的数量),但这个数组的元素是 30 个 memberinfo 的数组而不是一个 memberinfo。我不明白这个 $q.all() 调用是如何与 previous-level $q.all.
混合在一起的
数据结构大致是这样
- documents [ ] ($http => 30 responses)
- music.musicid
- music.rightHolders [ ] ($http => 1, 2, 3 responses)
- rightholder.rights
- rightholder.member ($http => 1 response)
- member.memberinfo
感谢任何帮助。谢谢!
更新:感谢您的回答,它非常有效。这是更新后的代码,以及以不同方式格式化数据的迁移服务(正在进行一些数据库迁移在)。我把它排除在第一个例子之外,但你的回答给了我这个简洁的语法。
angular.module("myApp").service("database", ["$q", "$http", "migrate", function($q, $http, migrate) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberID: rightHolder.member
})).then(function(res) {
return (migrate.member(res.data[0]));
}).then(function(member) {
rightHolder.member = member;
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/rightHolders?where=" + JSON.stringify({
musicID: doc.musicID
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.rightHolder)
.map(getHolderMember)
)
);
}).then(function(rightHolders) {
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
},
{
subtitle: {
contains: q
}
}
]
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.music)
.map(getRightHolders)
)
);
}));
}
return (database);
}
我不太确定你是如何得到你所描述的结果的,但你的逻辑比它需要的更复杂,我认为这可能会导致你所看到的问题。您赋予 getRightsHolders
函数返回文档的责任,并且根据您上面的评论,听起来您之前让 getHolderMember()
函数执行类似的操作然后停止执行该操作。
我们可以通过让每个函数对其处理的实体负责并使用 .map()
而不是 for
来清理它(请不要对数组使用 for..in
) .
请试一试:
angular
.module("myapp")
.service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(memberId) {
var query = JSON.stringify({ memberid: memberid });
return $http.get("/api/members?where=" + query)
.then(function (res) {
return res.data[0];
});
}
function populateRightsHolderWithMember(rightsHolder) {
return getHolderMember(rightsHolder.memberid)
.then(function (member) {
rightsHolder.member = member;
return rightsHolder;
});
}
function getRightHolders(doc) {
var query = JSON.stringify({ musicid: doc.musicid });
return $http.get("/api/musicrights?where=" + query)
.then(function(res) {
return $q.all(res.data.map(populateRightsHolderWithMember));
});
}
function populateDocumentWithRightsHolders(document) {
return getRightsHolders(document)
.then(function(rightsHolders) {
document.rightsHolders = rightsHolders;
return document;
});
}
database.music = function(q) {
return $http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
return $q.all(res.data.map(populateDocumentWithRightsHolders));
});
}
return (database);
}]);
我正在建立一个基于音乐曲目数据库的网站。数据库如下:
- music table 包含 musicid 和标题
- musicrights table 包含 musicid 和 memberid
- members table 包含 memberid 和 memberinfo.
我正在尝试在我的 database
服务中构建一个 objects 数组,其中每个条目代表一个包含其权利人的曲目(包含关于一个权利人的信息,但不包含他的名字)及其会员信息(包含姓名等)。后台是sailsjs,代码如下:
angular.module("myapp").service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberid: rightHolder.memberid
})).then(function (res) {
rightHolder.member = res.data[0];
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/musicrights?where=" + JSON.stringify({
musicid: doc.musicid
})).then(function(res) {
// array of promises :
// each rightholder of a document has to solve member info
var rightHolders = [];
for (var i in res.data) {
var rightHolder = {
member: res.data[i].memberid,
type: res.data[i].membertype,
rights: res.data[i].memberrights
};
rightHolders.push(getHolderMember(rightHolder));
}
return ($q.all(rightHolders));
}).then(function(rightHolders) {
// expected array of one or two rightholders,
// enriched with member information
// actually returns array of one or two arrays of 30 members
// without rightholder info
console.log(rightHolders);
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
// array of 30 promises :
// each one of 30 documents has to resolve its rightholders
var documents = [];
for (var i in res.data) {
documents.push(getRightHolders(res.data[i]));
}
return ($q.all(documents));
}));
}
return (database);
}]);
第一组 promise 似乎按预期工作,但 getRightHolders 中的第二组不是。奇怪的是,这个函数 returns 一个数组,其中包含一个或两个 promises,它们是 rightHolders waiting for their memberinfo。但是在我 console.log 响应的回调中,我得到一个或两个数组(根据推送的承诺的数量),但这个数组的元素是 30 个 memberinfo 的数组而不是一个 memberinfo。我不明白这个 $q.all() 调用是如何与 previous-level $q.all.
混合在一起的数据结构大致是这样
- documents [ ] ($http => 30 responses)
- music.musicid
- music.rightHolders [ ] ($http => 1, 2, 3 responses)
- rightholder.rights
- rightholder.member ($http => 1 response)
- member.memberinfo
感谢任何帮助。谢谢!
更新:感谢您的回答,它非常有效。这是更新后的代码,以及以不同方式格式化数据的迁移服务(正在进行一些数据库迁移在)。我把它排除在第一个例子之外,但你的回答给了我这个简洁的语法。
angular.module("myApp").service("database", ["$q", "$http", "migrate", function($q, $http, migrate) {
var database = {};
function getHolderMember(rightHolder) {
return ($http.get("/api/members?where=" + JSON.stringify({
memberID: rightHolder.member
})).then(function(res) {
return (migrate.member(res.data[0]));
}).then(function(member) {
rightHolder.member = member;
return (rightHolder);
}));
}
function getRightHolders(doc) {
return ($http.get("/api/rightHolders?where=" + JSON.stringify({
musicID: doc.musicID
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.rightHolder)
.map(getHolderMember)
)
);
}).then(function(rightHolders) {
doc.rightHolders = rightHolders;
return (doc);
}));
}
database.music = function(q) {
return ($http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
},
{
subtitle: {
contains: q
}
}
]
})).then(function(res) {
return (
$q.all(res.data
.map(migrate.music)
.map(getRightHolders)
)
);
}));
}
return (database);
}
我不太确定你是如何得到你所描述的结果的,但你的逻辑比它需要的更复杂,我认为这可能会导致你所看到的问题。您赋予 getRightsHolders
函数返回文档的责任,并且根据您上面的评论,听起来您之前让 getHolderMember()
函数执行类似的操作然后停止执行该操作。
我们可以通过让每个函数对其处理的实体负责并使用 .map()
而不是 for
来清理它(请不要对数组使用 for..in
) .
请试一试:
angular
.module("myapp")
.service("database", ["$q", "$http", function($q, $http) {
var database = {};
function getHolderMember(memberId) {
var query = JSON.stringify({ memberid: memberid });
return $http.get("/api/members?where=" + query)
.then(function (res) {
return res.data[0];
});
}
function populateRightsHolderWithMember(rightsHolder) {
return getHolderMember(rightsHolder.memberid)
.then(function (member) {
rightsHolder.member = member;
return rightsHolder;
});
}
function getRightHolders(doc) {
var query = JSON.stringify({ musicid: doc.musicid });
return $http.get("/api/musicrights?where=" + query)
.then(function(res) {
return $q.all(res.data.map(populateRightsHolderWithMember));
});
}
function populateDocumentWithRightsHolders(document) {
return getRightsHolders(document)
.then(function(rightsHolders) {
document.rightsHolders = rightsHolders;
return document;
});
}
database.music = function(q) {
return $http.get("/api/music?where=" + JSON.stringify({
or: [{
title: {
contains: q
}
}, {
subtitle: {
contains: q
}
}]
})).then(function(res) {
return $q.all(res.data.map(populateDocumentWithRightsHolders));
});
}
return (database);
}]);