首頁  >  問答  >  主體

標題重寫為:遞歸非同步函數無法傳回值

<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 孩子 = 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 = 孩子[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 天前489

全部回覆(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
  • 取消回覆