You need to enable JavaScript to run this app. 为何我的异步函数中await未正常生效?递归未完成就提前返回结果
优惠活动
大模型
产品
解决方案
定价
更多

为何我的异步函数中await未正常生效?递归未完成就提前返回结果

代码提前返回的根因

两个核心错误叠加,导致await链路完全失效:

  • 首先是大家最容易踩的forEach异步陷阱:forEach是完全同步的遍历方法,它根本不会感知传入的回调是不是async函数,触发完一轮回调就立刻往下走,完全不会等回调里的await执行完成。你在forEach里写的递归调用,实际上是在“后台”跑的,外层逻辑根本没等它结束。另外你在回调里写的famillesReliees = await getFamilies(...) 其实是多余操作——数组是引用类型,递归函数里对数组的push修改,会直接作用在原引用上,不需要反复重新赋值接收返回值。
  • 其次是你的Promise链路断了:你当前代码里的await strapi.query(...),只等待了「查询单条分类数据」这一个操作的完成。当查询拿到结果进了.then回调后,你启动的那些子递归查询是没有被外层await“捕获”的,所以.then回调执行完(此时里面的异步递归根本还在跑),整个getFamilies函数就直接走到return语句,把还没收集完全的数组返回给上层了。
可行的修正方案

把同步的forEach替换成可等待的遍历逻辑,保证所有递归的异步任务都跑完了再返回结果:

  1. 优先用最直白的for...of循环(逻辑简单,顺序执行所有递归,不容易出数组引用问题),修正后代码如下:
const getFamilies = async function (familyId, famillesReliees = []) {
    // 直接await接查询结果,不要嵌套then,Promise链路更清晰
    const res = await strapi.query('famille-de-materiel').findOne({ id: familyId })
    // 没有子分类,直接收集当前ID
    if (!res.cats_enfant?.length) {
        famillesReliees.push(res.id)
        return famillesReliees
    }
    // 用for...of遍历,每一个递归调用都会被完整等待
    for (const enfant of res.cats_enfant) {
        await getFamilies(enfant.id, famillesReliees)
    }
    return famillesReliees
}

async search() {
    const value = await getFamilies(2, [])
    return value
}
  1. 如果子分类节点很多、查询之间没有先后依赖,可以用Promise.all并行执行所有子递归,减少整体等待时间:
// 替换上面for...of部分的代码即可
await Promise.all(
    res.cats_enfant.map(enfant => getFamilies(enfant.id, famillesReliees))
)

注意:不要在async递归的场景里用forEach,这是异步编程里非常常见的踩坑点——forEach没有内置的等待异步任务的能力,你写在回调里的await永远不会被外层逻辑感知。

内容的提问来源于stack exchange,提问作者ermat77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.06 08:36:07