标题重写为:递归异步函数无法返回值
P粉729518806
P粉729518806 2023-08-29 21:11:13
[MySQL讨论组]

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

+----+-------------------+-----------+----------+-----------+---------------------+
| id | task              | completed | parentid | createdby | createdat           |
+----+-------------------+-----------+----------+-----------+---------------------+
|  1 | 清洁公寓          |         0 |     NULL |         1 | 2022-03-24 00:47:33 |
|  2 | 清洁浴室          |         0 |        1 |         1 | 2022-03-24 00:47:33 |
|  3 | 清洁厨房          |         0 |        1 |         1 | 2022-03-24 00:47:33 |
|  4 | 洗淋浴器          |         0 |        2 |         1 | 2022-03-24 00:47:33 |
|  5 | 洗马桶            |         0 |        2 |         1 | 2022-03-24 00:47:33 |
|  6 | 清洁玻璃窗格      |         1 |        4 |         1 | 2022-03-24 00:47:33 |
|  7 | 清洁水龙头        |         0 |        4 |         1 | 2022-03-24 00:47:33 |
|  8 | 清洁水槽          |         0 |        3 |         1 | 2022-03-24 00:47:33 |
|  9 | 倒垃圾            |         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: '清洁公寓',
    completed: 0,
    parentid: null,
    createdby: 1,
    createdat: 2022-03-23T23:47:33.000Z,
    children: [ undefined, undefined ]
  }
]

简而言之,我希望得到的结果如下:

{
    id: 1,
    task: '清洁公寓',
    completed: 0,
    parentid: null,
    createdby: 1,
    createdat: 2022-03-23T23:47:33.000Z,
    children: [ 
        {
            id: 2,
            task: '清洁浴室',
            completed: 0,
            parentid: 1,
            createdby: 1,
            createdat: 2022-03-23T23:47:33.000Z,
            children: [ 
                {
                    id: 4,
                    task: '洗淋浴器',
                    completed: 0,
                    parentid: 2,
                    createdby: 1,
                    createdat: 2022-03-23T23:47:33.000Z,
                    children: [ ... ]
                  },
                  {
                    id: 5,
                    task: '洗马桶',
                    completed: 0,
                    parentid: 2,
                    createdby: 1,
                    createdat: 2022-03-23T23:47:33.000Z,
                    children: [ ... ]
                  },
            ]
          },
          {
            id: 3,
            task: '清洁厨房',
            completed: 0,
            parentid: 1,
            createdby: 1,
            createdat: 2022-03-23T23:47:33.000Z,
            children: [ ... ]
          },
        
        
  }

有什么建议吗?

P粉729518806
P粉729518806

全部回复(2)
P粉970736384

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

首先,您需要

await comp(child.id);

但您还需要等待每个子项完成运行。

Promise.all(array)

将等待您传递给它的数组中的每个承诺完成,而children[0].map(async () => {})将返回一个承诺数组。继续等待它,您应该就可以了。

P粉596191963

实际上,你的代码唯一的问题是你没有等待来自异步函数comp()的结果。 map()将返回一个Promise数组,你需要等待所有这些Promise,可以使用Promise.all()来实现。 Promise.all()返回一个Promise,当传递给Promise.all()的数组中的所有Promise都被解决时,该Promise将被解决。如果你等待它,你的children数组将按照你的期望传播。

这是使用Promise.all()的代码。因为我目前没有一个合适的数据库准备好,所以我用一个具有人工延迟的函数的异步调用替换了你所有的数据库异步调用,这样你就可以看到如何等待这些调用以及结果是否被真正等待。

const data = [
  {
    id: 1,
    task: "清洁公寓",
    completed: 0,
    parentid: null,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
  {
    id: 2,
    task: "清洁浴室",
    completed: 0,
    parentid: 1,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
  {
    id: 3,
    task: "清洁厨房",
    completed: 0,
    parentid: 1,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
  {
    id: 4,
    task: "洗淋浴器",
    completed: 0,
    parentid: 2,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
  {
    id: 5,
    task: "清洗马桶",
    completed: 0,
    parentid: 2,
    createdby: 1,
    createDate: "2022-03-24 00:47:33",
  },
  {
    id: 6,
    task: "清洁玻璃窗",
    completed: 1,
    parentid: 4,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
  {
    id: 7,
    task: "清洁水龙头",
    completed: 0,
    parentid: 4,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
  {
    id: 8,
    task: "清洁水槽",
    completed: 0,
    parentid: 3,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
  {
    id: 9,
    task: "倒垃圾",
    completed: 1,
    parentid: 3,
    createdby: 1,
    createdat: "2022-03-24 00:47:33",
  },
];

async function comp(tasks, taskId) {
  // 在这里执行你的数据库调用(这里只是模拟延迟,但函数是异步的,所以结果将保持不变)
  var task = await queryFind(tasks, taskId);
  var children = await queryFilter(tasks, taskId);

  // map()返回一个Promise数组,因为comp()返回一个Promise
  // Promise.all()返回一个Promise,当数组中的所有Promise都解决时返回
  task.children = await Promise.all(
    children.map((child) => comp(tasks, child.id))
  );

  return task;
}

// 这个函数模拟了一个异步的数据库访问。
async function queryFind(tasks, taskId) {
  // 等待100毫秒(模拟延迟)
  await sleep(100);
  return tasks.find((task) => task.id === taskId);
}

// 这个函数模拟了一个异步的数据库访问。
async function queryFilter(tasks, taskId) {
  // 等待100毫秒(模拟延迟)
  await sleep(100);
  return tasks.filter((t) => t.parentid === taskId);
}

// 延迟执行,这里应该模拟网络延迟
async function sleep(ms) {
  return new Promise((resolve) => setTimeout(() => resolve(), ms));
}

// 从ID为1的任务开始;需要将函数调用包装在一个异步方法中才能使用await
(async () => {
  const test = await comp(data, 1);
  console.log(JSON.stringify(test, null, 4));
})();
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号