首页  >  问答  >  正文

标题重写为:递归异步函数无法返回值

<p>我正在制作一个递归异步函数,该函数正在运行一个mysql查询。这是我正在使用的数据库:</p> <pre class="brush:php;toolbar:false;">+----+-------------------+-----------+----------+-----------+---------------------+ | 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 | +----+-------------------+-----------+----------+-----------+---------------------+</pre> <p>如果我将这个数据库存储在一个数组中,我可以运行这个函数:</p> <pre class="brush:php;toolbar:false;">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 }</pre> <p>来递归地将子任务嵌套到主任务中。</p> <p>问题是我对异步函数的理解不够好。</p> <p>这是我目前的进展:</p> <pre class="brush:php;toolbar:false;">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]) }</pre> <p>但是这返回了带有未定义子任务的任务:</p> <pre class="brush:php;toolbar:false;">[ { id: 1, task: '清洁公寓', completed: 0, parentid: null, createdby: 1, createdat: 2022-03-23T23:47:33.000Z, children: [ undefined, undefined ] } ]</pre> <p>简而言之,我希望得到的结果如下:</p> <pre class="brush:php;toolbar:false;">{ 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: [ ... ] }, }</pre> <p>有什么建议吗?</p>
P粉729518806P粉729518806391 天前480

全部回复(2)我来回复

  • P粉970736384

    P粉9707363842023-08-30 12:38:29

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

    首先,您需要

    await comp(child.id);

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

    Promise.all(array)

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

    回复
    0
  • P粉596191963

    P粉5961919632023-08-30 10:50:07

    实际上,你的代码唯一的问题是你没有等待来自异步函数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));
    })();

    回复
    0
  • 取消回复