You need to enable JavaScript to run this app. Discord.js中收集反应用户时嵌套异步函数内数组返回为空的问题
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js中收集反应用户时嵌套异步函数内数组返回为空的问题

问题核心原因

问题不是变量作用域导致的,本质是异步执行时序不匹配:

  • result变量定义在getUsersWhoReacted的函数作用域内,嵌套的回调函数可以通过闭包正常访问、修改这个变量,不存在作用域隔离的问题——如果真的是作用域问题,你在嵌套回调里操作result时会直接抛出引用错误,根本不可能成功在回调里打印出已经收集满用户ID的数组。
  • 问题的核心逻辑链条:
    • Discord.js的Collection.each()是同步遍历方法,本身不会等待传入的异步回调执行完成
    • 你传给each()的回调是async函数,当执行到await reaction.users.fetch()时,会直接挂起当前回调的执行,把控制权交还给外层的同步代码
    • 外层代码不会等待所有挂起的异步回调跑完,会立刻继续执行到外层的console.log(result),这时候所有用户抓取的网络请求还没返回,result数组还没有被推入任何数据,自然打印的是空数组
    • 等后续所有异步请求完成、回调依次执行并往result里push数据的时候,外层代码早就执行完了,所以你在回调里能看到完整的数组,但外层永远拿不到最终的填充结果。
可行解决方案

方案1:用Promise.all统一等待所有用户抓取任务完成

这是最贴合Discord.js Collection API的写法,把每个反应对应的抓取操作转成独立Promise,统一等待所有任务跑完再返回结果,附带去重逻辑避免同一个用户被多次统计:

const getUsersWhoReacted = async (reactionCollection) => {
    // 为每个反应生成一个独立的异步用户抓取任务
    const userFetchTasks = reactionCollection.map(async (reaction) => {
        const reactedUsers = await reaction.users.fetch();
        // 返回当前反应关联的用户ID列表
        return reactedUsers.map(user => user.id);
    });

    // 等待所有抓取任务完成
    const allReactionUserArrays = await Promise.all(userFetchTasks);
    // 拍平二维数组、去重,得到最终的独立用户ID集合
    const uniqueUserIds = [...new Set(allReactionUserArrays.flat())];
    
    console.log(uniqueUserIds);
    // 可以正常把最终结果返回给调用方
    return uniqueUserIds;
}

方案2:沿用原有each遍历逻辑的适配写法

如果习惯使用each()的遍历风格,可以手动收集所有挂起的异步任务,等全部执行完成后再返回结果:

const getUsersWhoReacted = async (reactionCollection) => {
    let result = [];
    const pendingFetchTasks = [];

    reactionCollection.each((reaction) => {
        // 将每个反应的抓取逻辑封装成可追踪的Promise,存入任务队列
        const fetchTask = (async () => {
            const users = await reaction.users.fetch();
            users.forEach(user => result.push(user.id));
        })();
        pendingFetchTasks.push(fetchTask);
    });

    // 阻塞等待所有异步抓取任务执行完成
    await Promise.all(pendingFetchTasks);

    // 此时result已经完成所有数据填充,可以正常返回
    const uniqueUserIds = [...new Set(result)];
    console.log(uniqueUserIds);
    return uniqueUserIds;
}

常见避坑提醒

不要直接在each()的参数里写async回调——这种写法相当于“发射即不管”的异步任务,each()遍历完不会等待这些任务执行,和你原来遇到的空数组问题完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.25 00:36:04