search

Home  >  Q&A  >  body text

Title rewritten as: Recursive async function cannot return value

<p>I'm making a recursive async function that is running a mysql query. This is the database I'm using: </p> <pre class="brush:php;toolbar:false;"> ---- ------------------- ---------- - ---------- ---------- ----------------------- | id | task | completed | parentid | createdby | createdat | ---- ------------------- ----------- ---------- ------ ----------------------------- | 1 | Clean Apartment | 0 | NULL | 1 | 2022-03-24 00:47:33 | | 2 | Clean the bathroom | 0 | 1 | 1 | 2022-03-24 00:47:33 | | 3 | Clean the kitchen | 0 | 1 | 1 | 2022-03-24 00:47:33 | | 4 | Take a shower | 0 | 2 | 1 | 2022-03-24 00:47:33 | | 5 | Wash the toilet | 0 | 2 | 1 | 2022-03-24 00:47:33 | | 6 | Cleaning glass panes | 1 | 4 | 1 | 2022-03-24 00:47:33 | | 7 | Clean faucets | 0 | 4 | 1 | 2022-03-24 00:47:33 | | 8 | Clean the sink | 0 | 3 | 1 | 2022-03-24 00:47:33 | | 9 | Take out the trash | 1 | 3 | 1 | 2022-03-24 00:47:33 | ---- ------------------- ----------- ---------- ------ ----- --------------------- </pre> <p>If I store this database in an array, I can run this function: </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> to recursively nest subtasks into the main task. </p> <p>The problem is that I don't understand asynchronous functions well enough.</p> <p>This is my progress so far: </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>But this returns a task with undefined subtasks: </p> <pre class="brush:php;toolbar:false;">[ { id: 1, task: 'Clean the apartment', completed: 0, parentid: null, createdby: 1, createdat: 2022-03-23T23:47:33.000Z, children: [ undefined, undefined ] } ]</pre> <p>In a nutshell, what I want is the following: </p> <pre class="brush:php;toolbar:false;">{ id: 1, task: 'Clean the apartment', completed: 0, parentid: null, createdby: 1, createdat: 2022-03-23T23:47:33.000Z, children: [ { id: 2, task: 'Clean the 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 the kitchen', completed: 0, parentid: 1, createdby: 1, createdat: 2022-03-23T23:47:33.000Z, children: [ ... ] }, }</pre> <p>Any suggestions? </p>
P粉729518806P粉729518806472 days ago547

reply all(2)I'll reply

  • P粉970736384

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

    You are waiting for the original two expected items to finish running before starting the next recursive call and then printing without waiting for the recursive call itself.

    First, you need

    await comp(child.id);

    But you also need to wait for each child to finish running.

    Promise.all(array)

    will wait for each promise in the array you pass it to complete, while children[0].map(async () => {}) will return an array of promises. Just keep waiting for it and you should be fine.

    reply
    0
  • P粉596191963

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

    Actually, the only problem with your code is that you are not waiting for the result from the async function comp(). map() will return an array of Promise, you need to wait for all these Promise, you can use Promise.all() to achieve this. Promise.all() Returns a Promise that will be resolved when all Promises in the array passed to Promise.all() have been resolved. If you wait for it, your children array will be propagated as you expect.

    This is the code using Promise.all(). Since I don't currently have a proper database ready, I replaced all of your database async calls with an asynchronous call to a function with an artificial delay so you can see how the calls are being waited for and whether the results are actually being waited for.

    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));
    })();

    reply
    0
  • Cancelreply