如何使用Promise填充层次结构,其中每个级别都需要满足之前的级别?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用Promise填充层次结构,其中每个级别都需要满足之前的级别?相关的知识,希望对你有一定的参考价值。
这是我尝试过的第一个代码版本。我已经尝试了很多其他的东西,比如互斥,在任何地方添加catch块,以及Promise反模式,但我似乎无法克服这种心理或语法障碍:
populateJoins() {
let promises = [];
for (let c in this.columns) {
let transformColumn = this.columns[c];
if (transformColumn.joins) {
let joinPointer = this.databaseObject;
for (let j in transformColumn.joins) {
let join = transformColumn.joins[j];
if (joinPointer[join.as] != null) {
joinPointer = joinPointer.dataValues[join.as];
} else {
if (this.requestQuery[toCamelCase(join.as) + 'Id']) {
promises.push(
join.model.findOne({where: {id: this.requestQuery[toCamelCase(join.as) + 'Id']}})
.then((tmp) => {
joinPointer.dataValues[join.as] = tmp;
}));
} else if (joinPointer[toSnakeCase(join.as) + '_id']) {
promises.push(
join.model.findOne({where: {id: joinPointer[toSnakeCase(join.as) + '_id']}})
.then((tmp) => {
joinPointer.dataValues[join.as] = tmp;
}));
}
}
}
}
}
return Promises.all(promises);
}
这是this.columns
的结构:
child1Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child1'
}],
hidden: true
},
child2Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
}],
hidden: true
},
child1Status1Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child1'
},{
model: Database.getInstance().getModel('status1'),
as: 'Status1'
}],
hidden: true
},
child1Status2Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child1'
},{
model: Database.getInstance().getModel('status2'),
as: 'Grandchild2'
}],
hidden: true
},
serverName: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child1'),
as: 'Child2'
},{
model: Database.getInstance().getModel('grandchild'),
as: 'Grandchild'
},{
model: Database.getInstance().getModel('great_grandchild'),
as: 'GreatGrandchild'
}],
hidden: true
},
child2Status1Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
},{
model: Database.getInstance().getModel('status1'),
as: 'Grandchild1'
}],
hidden: true
},
child2Status2Name: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
},{
model: Database.getInstance().getModel('status2'),
as: 'Grandchild2'
}],
hidden: true
},
archetypeName: {
name: 'name',
forceSelect: true,
joins: [{
model: Database.getInstance().getModel('child2'),
as: 'Child2'
},{
model: Database.getInstance().getModel('archetype'),
as: 'Archetype'
},{
model: Database.getInstance().getModel('archetype'),
as: 'ArchetypeLink'
}],
hidden: true
},
因此,对于我已经学过的东西,joinPointer[join.as] != null
永远不会阻止重复的Child
数据库调用被触发,因为在promises完成解析之前不会填充该属性。
同样地,没有孙子会填充,因为他们必须等待孩子们居住,如果孙子们先完成,那么他们永远不会进入子对象。对曾孙子来说也是如此。
我读了this answer,他说,“如果你已经将它们放在一个数组中,那么它们就已经在执行了。”我知道Promise的内容已经解决,这就是为什么在其他代码中我总是使用数字索引来填充对象,即jsonObject['list'][i]['anotherList'][j] = ...;
,但我不知道我怎么能在这里做到这一点。
我已经在这方面工作了一段时间并且没有提出解决方案,所以任何可行的代码都不仅仅是值得赞赏的。
问题中的代码很难遵循,但看起来你要做的事情相当简单,即串行执行一组异步findOne
查询,逐步构建一个包含返回结果的更深层次的层次结构。
如果是这样,那么:
- 你可以使用
reduce()
模式,参见“The Collection Kerfuffle”here。 - 完整的
.columns
对象是不必要的 - 你只需要.columns.greatGrandchildName.joins
。
代码应至少看起来像这样:
populateJoin(joins) {
return joins.reduce((p, join) => {
return p.then(obj => {
let id = this.requestQuery[toCamelCase(join.as) + 'Id'] || obj[toSnakeCase(join.as) + '_id'] || obj[toSnakeCase(join.as + 's') + '_id'] || null;
if(id) {
return join.model.findOne({'where': { 'id': id }}).then(tmp => {
if (obj.dataValues[join.as]) {
return obj.dataValues[join.as];
} else {
obj.dataValues[join.as] = tmp;
return tmp; // 'tmp' will be `obj` at next iteration of the reduction.
}
return tmp; // 'tmp' will be `obj` at next iteration of the reduction.
});
} else {
return obj; // send unmodified obj to next iteration of the reduction.
}
});
}, Promise.resolve(this.databaseObject)) // starter promise for the reduction
.then(() => this.databaseObject); // useful though not essential to make the top level object available to the caller's .then() callback.
}
populateJoins() {
var promises = [];
for (let c in this.columns) {
let transformColumn = this.columns[c];
if (transformColumn.joins) {
promises.push(this.populateJoin(transformColumn.joins));
}
}
return Promise.all(promises);
}
以上是关于如何使用Promise填充层次结构,其中每个级别都需要满足之前的级别?的主要内容,如果未能解决你的问题,请参考以下文章
在 tibble 中的嵌套级别之间移动:如何引用存储在嵌套层次结构的上层中的数据