递归异步函数返回未定义



我正在制作一个运行mysql查询的递归异步函数。这是我正在使用的数据库:

+----+-------------------+-----------+----------+-----------+---------------------+
| id | task              | completed | parentid | createdby | createdat           |
+----+-------------------+-----------+----------+-----------+---------------------+
|  1 | Clean apartment   |         0 |     NULL |         1 | 2022-03-24 00:47:33 |
|  2 | Clean bathroom    |         0 |        1 |         1 | 2022-03-24 00:47:33 |
|  3 | Clean kitchen     |         0 |        1 |         1 | 2022-03-24 00:47:33 |
|  4 | Wash shower       |         0 |        2 |         1 | 2022-03-24 00:47:33 |
|  5 | Wash toilet       |         0 |        2 |         1 | 2022-03-24 00:47:33 |
|  6 | Clean glass panes |         1 |        4 |         1 | 2022-03-24 00:47:33 |
|  7 | Clean faucet      |         0 |        4 |         1 | 2022-03-24 00:47:33 |
|  8 | Clean sink        |         0 |        3 |         1 | 2022-03-24 00:47:33 |
|  9 | Take out trash    |         1 |        3 |         1 | 2022-03-24 00:47:33 |
+----+-------------------+-----------+----------+-----------+---------------------+

如果我把这个数据库存储在一个数组中,我可以运行这个函数:

function comp(tasks, taskId) {
var task = tasks.find(task => task.id === taskId)
var children = tasks.filter(t => t.parentId === taskId)
task.children = children.map(child => comp(tasks, child.id));
return task
}

以递归地将子任务嵌套到主任务中。

现在的问题是我对异步函数没有很好的理解。

这就是我现在所走的路:

async function comp(taskId) {
// SELECT * FROM tasks WHERE id = taskId
var task = await con.promise().query('select * from tasks where id = ' + taskId)

// SELECT * FROM tasks WHERE parentId = taskId
var children = await con.promise().query('select * from tasks where parentid = ' + taskId)

task[0][0].children = children[0].map(child => {
comp(child.id)
})
console.log(task[0])

}

但这会返回带有未定义子项的任务:

[
{
id: 1,
task: 'Clean apartment',
completed: 0,
parentid: null,
createdby: 1,
createdat: 2022-03-23T23:47:33.000Z,
children: [ undefined, undefined ]
}
]

简而言之,我想要的结果是这样的:

{
id: 1,
task: 'Clean apartment',
completed: 0,
parentid: null,
createdby: 1,
createdat: 2022-03-23T23:47:33.000Z,
children: [ 
{
id: 2,
task: 'Clean bathroom',
completed: 0,
parentid: 1,
createdby: 1,
createdat: 2022-03-23T23:47:33.000Z,
children: [ 
{
id: 4,
task: 'Wash shower',
completed: 0,
parentid: 2,
createdby: 1,
createdat: 2022-03-23T23:47:33.000Z,
children: [ ... ]
},
{
id: 5,
task: 'Wash toilet',
completed: 0,
parentid: 2,
createdby: 1,
createdat: 2022-03-23T23:47:33.000Z,
children: [ ... ]
},
]
},
{
id: 3,
task: 'Clean kitchen',
completed: 0,
parentid: 1,
createdby: 1,
createdat: 2022-03-23T23:47:33.000Z,
children: [ ... ]
},


}

有什么建议吗?

本质上,代码的唯一问题是不等待异步函数comp()的结果。map()将返回一个Promises数组,您需要等待使用Promise.all()可以完成的所有Promises。Promise.all()返回一个Promise,该Promise将在传递给Promise.all()的数组中的所有Promise都已结算时解析。如果您等待您的子数组将按照您的期望进行传播。

这是您使用Promise.all()的代码。因为我目前还没有准备好合适的数据库,所以我用对一个内置了人为延迟的函数的异步调用替换了您对数据库的所有异步调用,这样您就可以看到如何实际等待这些调用,并且实际正在等待结果。

const data = [
{
id: 1,
task: "Clean apartment",
completed: 0,
parentid: null,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
{
id: 2,
task: "Clean bathroom",
completed: 0,
parentid: 1,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
{
id: 3,
task: "Clean kitchen",
completed: 0,
parentid: 1,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
{
id: 4,
task: "Wash shower",
completed: 0,
parentid: 2,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
{
id: 5,
task: "Wash toilet",
completed: 0,
parentid: 2,
createdby: 1,
createDate: "2022-03-24 00:47:33",
},
{
id: 6,
task: "Clean glass panes",
completed: 1,
parentid: 4,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
{
id: 7,
task: "Clean faucet",
completed: 0,
parentid: 4,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
{
id: 8,
task: "Clean sink",
completed: 0,
parentid: 3,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
{
id: 9,
task: "Take out trash",
completed: 1,
parentid: 3,
createdby: 1,
createdat: "2022-03-24 00:47:33",
},
];
async function comp(tasks, taskId) {
// do your DB calls here (here just imitating the delay but the function are async to the result will remain the same)
var task = await queryFind(tasks, taskId);
var children = await queryFilter(tasks, taskId);
// map() returns an array of promises as comp() returns a promise
// Promise.all() returns a Promise that returns when all promises within the array are settled
task.children = await Promise.all(
children.map((child) => comp(tasks, child.id))
);
return task;
}
// this function immitates an async DB access.
async function queryFind(tasks, taskId) {
// wait for 100 milliseconds (imitate delay)
await sleep(100);
return tasks.find((task) => task.id === taskId);
}
// this function immitates an async DB access.
async function queryFilter(tasks, taskId) {
// wait for 100 milliseconds (imitate delay)
await sleep(100);
return tasks.filter((t) => t.parentid === taskId);
}
// delay execution. should imitage network delay here
async function sleep(ms) {
return new Promise((resolve) => setTimeout(() => resolve(), ms));
}
// Start at task with ID 1; need to wrap the function call in an async method to be able to use await
(async () => {
const test = await comp(data, 1);
console.log(JSON.stringify(test, null, 4));
})();

您正在等待原始的两个等待项完成运行,然后开始下一个递归调用,然后在不等待递归调用本身的情况下打印。

首先,你会想要

await comp(child.id);

但你也会希望等待每个孩子都完成跑步。

Promise.all(array)

将等待您传递到的数组中的每个promise完成,恰好children[0].map(async () => {})将返回一个promise数组。去啊,然后(a(也等着,你就应该做好准备了。

最新更新