给出一个简单的用户树:
users:
id | name | parent_id
1 | Bob | NULL
2 | Jan | 1
3 | Mat | 2
4 | Irene | 2
5 | Ellie | 2
6 | Laura | 5
7 | Uma | 6
我正试图用这段代码来实现它:
addChildren: function(db, treeUsers, parentId) {
const main = this;
var sql = Sql.select().from('users')
.where('parent_id = ?', parentId)
.toParam();
return db.execute(sql.text, sql.values)
.then(function([rs,meta]) {
rs.map(function(obj) {
treeUsers[obj.id] = obj;
});
return treeUsers;
});
},
getTreeUsers: function(db, depth) {
const main = this;
const rootNodeId = 1;
var treeUsers = {};
const getChildren = function(parentId) {
return main.addChildren(db, treeUsers, parentId).then(function(children) {
treeUsers = Object.assign(treeUsers, children);
--depth;
if(depth < 1) {
return Promise.resolve(treeUsers);
}
return Promise.all(Object.keys(children).map(function(id) {
return getChildren(id);
}));
};
return getChildren(rootNodeId);
});
所需的输出是这样的:
{
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
}
现在我变得更像这样:
[[ {
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
} ],
[ {
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
} ],
[ {
'2': { id: 2, name: 'Jan' , parent_id: 2 },
'3': { id: 3, name: 'Mat' , parent_id: 2 },
'4': { id: 4, name: 'Irene', parent_id: 2 },
'5': { id: 5, name: 'Ellie', parent_id: 2 },
'6': { id: 6, name: 'Laura', parent_id: 5 },
'7': { id: 7, name: 'Uma' , parent_id: 6 }
} ] ... ]
我很肯定问题是Promise.all(getChildren(..))
调用,但我不确定如何重构,以便我完全回到最后的结果集。
答案 0 :(得分:1)
一些问题:
您在两种方法中都会改变treeUsers
对象,这意味着您解决的对象以后仍会发生变异。请注意,对于getTreeUsers
的一次调用,您只能拥有该对象的一个实例。请注意以下内容中的分配:
treeUsers = Object.assign(treeUsers, children);
没有做任何事情,因为Object.assign
已经改变了第一个参数。
Promise.all
解析为数组值,其中每个元素都包含treeUsers
对象。当它被所有单独的调用变异时,所有这些数组条目都指向相同的对象引用,解释了你看到的重复。depth
是每次调用getChildren
时共有的变量。将它作为参数传递会更安全,以确保兄弟姐妹使用depth
的相同值进行扩展我只是避免传递treeUsers
对象,因为它应该只是解析后的值。让每个承诺解决孩子们可以&#34;看到&#34;并在每个Promise.all
承诺解决后整合结果。
以下是这样的看法:
addChildren: function(db, treeUsers, parentId) {
const main = this,
sql = Sql.select().from('users')
.where('parent_id = ?', parentId)
.toParam();
return db.execute(sql.text, sql.values).then(function([rs,meta]) {
// Create a new(!) object and return it
return Object.assign(...rs.map(function(obj) {
return { [obj.id]: obj };
}));
});
},
getTreeUsers: function(db, depth) {
const main = this,
rootNodeId = 1;
const getChildren = function(parentId, depth) { // pass depth
return main.addChildren(db, parentId).then(function(children) {
if (depth <= 1) {
return children; // only the children. No need for Promise.resolve
}
return Promise.all(Object.keys(children).map(function(id) {
return getChildren(id, depth - 1); // pass depth
})).then(arr => Object.assign(children, ...arr)); // consolidate
});
}
return getChildren(rootNodeId, depth);
}
答案 1 :(得分:0)
是的,Promise.all
始终返回所有结果值的数组。当你的调用都返回具有相同值treeUsers
的promises时,你会获得这些对象的数组。由于您始终希望getChildren
始终只返回该对象,因此您可以简化为
function getChildren(parentId) {
return main.addChildren(db, treeUsers, parentId).then(function(children) {
Object.assign(treeUsers, children);
// when `children` is empty, the recursion terminates here
return Promise.all(Object.keys(children).map(getChildren)).then(() =>
treeUsers
);
});
}
(当然这不会产生树形结构)