You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js从反应用户数组随机抽取返回undefined问题

Discord机器人抽奖返回undefined的问题修复

问题根源分析

你的代码存在几个核心问题,导致抽奖结果返回undefined:

  1. 同步循环与异步延迟冲突:delay(1000)未使用await,导致for循环瞬间执行完毕,直接触发结束逻辑时,reactionUsers可能还未收集到任何用户。
  2. 用户去重逻辑失效:直接用user === reactionUsers[i]比较对象引用,Discord的User对象每次获取都是新实例,无法正确判断重复。
  3. 随机索引越界风险:Math.ceil(Math.random() * reactionUsers.length)在数组为空时会得到0,reactionUsers[0-1]即reactionUsers[-1]会返回undefined;数组非空时也可能取到等于数组长度的索引,同样导致越界。
  4. 倒计时变量冲突:直接修改timeRemaining会和反应收集器的time参数冲突,同步循环无法实现正确的倒计时更新。

修正后的代码

const delay = ms => new Promise(res => setTimeout(res, ms));
const collector = giveawayMessage.createReactionCollector(filter, { time: timeRemaining });
const reactionUserIds = new Set(); // 用Set自动去重,存储用户ID避免对象引用问题

// 初始添加👍反应
await giveawayMessage.react('👍');

// 收集有效参与者(排除机器人)
collector.on('collect', (reaction, user) => {
    if (reaction.emoji.name === '👍' && !user.bot) {
        reactionUserIds.add(user.id);
    }
});

// 异步更新倒计时
async function updateCountdown() {
    let remaining = timeRemaining;
    while (remaining > 0) {
        await delay(1000);
        remaining--;
        
        // 计算格式化剩余时间
        const numDays = Math.trunc(remaining / 86400);
        const numHours = Math.trunc((remaining - numDays * 86400) / 3600);
        const numMinutes = Math.trunc((remaining - numDays * 86400 - numHours * 3600) / 60);
        const numSeconds = remaining - numDays * 86400 - numHours * 3600 - numMinutes * 60;
        const timeFormatted = `${numDays}d ${numHours}h ${numMinutes}m ${numSeconds}s`;
        
        // 更新消息embed
        const updatedEmbed = EmbedBuilder.from(embed)
            .setFields(
                { name: 'Prize', value: `${interaction.options.getString('prize')}` },
                { name: 'Time Remaining', value: timeFormatted }
            );
        await giveawayMessage.edit({ embeds: [updatedEmbed] });
    }
}

// 等待收集器结束和倒计时完成
await Promise.all([collector.stop(), updateCountdown()]);

// 执行抽奖逻辑
const userIdList = Array.from(reactionUserIds);
if (userIdList.length === 0) {
    // 无有效参与者的情况
    const finalEmbed = EmbedBuilder.from(embed)
        .addFields({ name: 'Winner', value: 'No valid participants!' });
    await giveawayMessage.edit({ embeds: [finalEmbed] });
    return;
}

// 安全生成随机索引
const randomIndex = Math.floor(Math.random() * userIdList.length);
const winnerId = userIdList[randomIndex];
const winner = await interaction.guild.members.fetch(winnerId); // 获取完整用户对象

// 更新结果embed
const finalEmbed = EmbedBuilder.from(embed)
    .addFields({ name: 'Winner', value: `${winner}` });
await giveawayMessage.edit({ embeds: [finalEmbed] });

关键改进点

  • 用Set自动去重:通过存储用户ID替代User对象,彻底解决对象引用比较失效的问题。
  • 异步倒计时:使用async/await确保每次延迟1秒后再更新倒计时,避免循环瞬间执行完毕。
  • 安全随机索引:Math.floor(Math.random() * 数组长度)确保索引始终在0到数组长度-1的范围内,不会越界。
  • 分离逻辑:用Promise.all等待反应收集和倒计时完成,确保所有参与者都被收集后再抽奖。
  • 边界处理:增加无参与者的情况判断,避免返回undefined。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 17:55:08