异步加递归问题,await被跳过?

新手上路,请多包涵

函数recursive 是异步加递归
理想状态是:在函数updateParams调用 await函数recursive执行完后再执行后面代码。
实际:函数recursive还没执行完后面的代码就执行了


    async updateParams(type, keyword) {
        if(this.treeData.length === 0) {
          await this.recursive(this.vNode.childNodes)
          console.log("🐇  updateParams  this.recursive👻", this.treeData)
        }
        console.log('查找-');
        const data = this.treeData.find(item => item.path === type)
        this.setParams(data)
        const query = Object.assign({}, this.params,{
          current : 1,
          size : 10000,
          data : keyword
        })
        const res = await fetchPage(query)
        this.ids = res.data.data.records.map(i => i.id)
      },

 async recursive(data) {
        try {
          for (let i = 0; i < data.length; i++) {
          const item = data[i]
          if(item.isLeaf) {// 没有下级
            const data = item.data ? item.data : item
            this.treeData.push(data)
          }else {
            const { data } = await fetchArchiveTree(this.getQueryParams(item))
            data.data.forEach(item => {
              if(!item.isLeaf) {
                const Arr = [item]
                this.recursive(Arr)
              }
              this.treeData.push(item)
            });
          }
        }
        } catch (error) {
          console.log('获取树形数据失败',error);
        }
        console.log('数据收集完毕');
      },

getQueryParams(res) {
    const data = res.data ? res.data : res
    return {
      id: data.id,
      filter: data.filter || '',
      path: data.path || '',
      fondsCode: this.current_fonds
    }
  },
阅读 460
avatarAI BotBETA

这个问题是由于 JavaScript 的异步递归导致的。在函数 updateParams 中,this.recursive(this.vNode.childNodes) 被调用了,但是并没有等待它完成就执行了后面的代码。这是因为 JavaScript 的异步特性,当一个函数被标记为 async,那么它的所有异步操作都不会阻止后面的代码执行。

在你的代码中,递归调用 this.recursive(Arr)this.recursive(data) 完成之前就执行了,这就是为什么 console.log("🐇 updateParams this.recursive👻", this.treeData) 在递归函数完成之前就被执行了。

要解决这个问题,你需要在 updateParams 函数中等待 recursive 函数完成。为了实现这一点,你需要将递归函数包装在一个 Promise 中,然后在 updateParams 函数中使用 await 来等待这个 Promise 完成。这样,后面的代码就不会在递归函数完成之前执行了。

下面是你可能需要修改的代码:

async updateParams(type, keyword) {
    if(this.treeData.length === 0) {
      await this.recursiveWrapper(this.vNode.childNodes)
      console.log("🐇  updateParams  this.recursive👻", this.treeData)
    }
    console.log('查找-');
    const data = this.treeData.find(item => item.path === type)
    this.setParams(data)
    const query = Object.assign({}, this.params,{
      current : 1,
      size : 10000,
      data : keyword
    })
    const res = await fetchPage(query)
    this.ids = res.data.data.records.map(i => i.id)
  },
  recursiveWrapper(data) {
    return new Promise((resolve, reject) => {
      this.recursive(data).then(() => {
        resolve()  // 当 recursive 完成时,调用 resolve()
      }).catch(error => {
        reject(error)  // 当 recursive 失败时,调用 reject()
      })
    })
  },
  async recursive(data) {
    try {
      for (let i = 0; i < data.length; i++) {
      const item = data[i]
      if(item.isLeaf) {// 没有下级
        const data = item.data ? item.data : item
        this.treeData.push(data)
      }else {
        const { data } = await fetchArchiveTree(this.getQueryParams(item))
        data.data.forEach(item => {
          if(!item.isLeaf) {
            const Arr = [item]
            this.recursive(Arr)  // 递归调用,但是不直接返回结果,而是等待 Promise 完成
          }
          this.treeData.push(item)
        });
      }
      } catch (error) {
        console.log('获取树形数据失败',error);
      } finally {  // 使用 finally 来确保无论是否有错误,都能结束递归调用并返回结果
        console.log('数据收集完毕');  // 这行代码会在所有的递归调用结束后执行一次,而不是在每个递归调用结束后执行一次。你可能需要调整这个代码来满足你的需求。
        return Promise.resolve();  // 返回一个已经解决的 Promise,这样 recursiveWrapper 就可以等待这个 Promise 完成了。
      }
    } catch (error) {  // 这个 catch 块会在 recursive 函数抛出错误时执行。你可以在这里处理错误。
      console.log('获取树形数据失败',error);  // 这行代码会在 recursive 函数抛出错误时执行一次。你可能需要调整这个代码来满足你的需求。
1 个回答

recursive 方法内部实现的问题,Array 的 forEach 循环是不支持 async/await 的,所以应该把 forEach 部分换成 for 循环再配合 await ,如下:

 async recursive(data) {
        try {
          for (let i = 0; i < data.length; i++) {
          const item = data[i]
          if(item.isLeaf) {// 没有下级
            const data = item.data ? item.data : item
            this.treeData.push(data)
          }else {
            const { data } = await fetchArchiveTree(this.getQueryParams(item))
            for (let item of data.data) {
                if(!item.isLeaf) {
                    const Arr = [item]
                    await this.recursive(Arr)
                }
                this.treeData.push(item)
            }
          }
        }
        } catch (error) {
          console.log('获取树形数据失败',error);
        }
        console.log('数据收集完毕');
      },
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题