返回未定义的递归异步函数
Recursive async function returning undefined
我正在制作一个 运行 宁 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])
}
但是这个 returns 带有未定义子项的任务:
[
{
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()
将 return 一个 Promise 数组,您将需要等待所有可以使用 Promise.all()
完成的承诺。 Promise.all()
return 是一个 Promise,当传递给 Promise.all()
的数组中的所有 Promise 都已解决时,它将解析。如果您 await 您的子数组将按您预期的方式传播。
这是您使用 Promise.all()
的代码。因为目前我还没有准备好合适的数据库,所以我用对具有人为延迟 built-in 的函数的异步调用替换了对数据库的所有异步调用,因此您可以看到如何实际等待那些和那个结果还真是等着呢
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);
但您还需要等待每个 child 完成 运行。
Promise.all(array)
将等待您传入的数组中的每个承诺完成,恰好 children[0].map(async () => {})
将 return 一个承诺数组。去啊,(a)等待那个,你应该被设置。
我正在制作一个 运行 宁 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])
}
但是这个 returns 带有未定义子项的任务:
[
{
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()
将 return 一个 Promise 数组,您将需要等待所有可以使用 Promise.all()
完成的承诺。 Promise.all()
return 是一个 Promise,当传递给 Promise.all()
的数组中的所有 Promise 都已解决时,它将解析。如果您 await 您的子数组将按您预期的方式传播。
这是您使用 Promise.all()
的代码。因为目前我还没有准备好合适的数据库,所以我用对具有人为延迟 built-in 的函数的异步调用替换了对数据库的所有异步调用,因此您可以看到如何实际等待那些和那个结果还真是等着呢
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);
但您还需要等待每个 child 完成 运行。
Promise.all(array)
将等待您传入的数组中的每个承诺完成,恰好 children[0].map(async () => {})
将 return 一个承诺数组。去啊,(a)等待那个,你应该被设置。