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

使用discord-buttons实现点击按钮编辑Discord bot消息更新烘焙小游戏进度

问题修复与代码优化方案

原代码存在的核心问题

  • 条件判断误用赋值运算符=:你所有if (eggs = 1)这类写法都是把eggs赋值为1,不是判断相等,会导致逻辑完全不符合预期,应该用全等运算符===
  • 重复注册事件监听:每次用户触发纸杯蛋糕制作逻辑时,都会给client新增一个clickButton事件监听,多次触发后会有多个监听同时执行,进度数值会出现混乱,还会造成内存泄漏
  • 重复代码冗余:所有编辑消息的内容只有进度数字不同,完全不需要写四层嵌套if,硬编码维护成本极高
  • 缺少边界控制:鸡蛋数量达标后没有禁用按钮,用户还能继续点击导致数值溢出;也没有校验点击者是否是发起制作的玩家,其他人可以恶意干扰进度
  • 异步操作未加await:button.reply.defer()是异步方法,不加await可能会出现未捕获的异步报错

优化后可直接使用的代码

// 统一转小写匹配
const itemNames = args.join(' ').toLowerCase();
console.log(itemNames);

if (itemNames === "cupcakes" || itemNames === "cupcake") {
    // 配置常量,后续改需求直接改这里就行
    const TOTAL_EGGS = 4;
    const BASE_PROMPT = "Cupcakes, ok! Don't mess this up, dummy... We need to start with the eggs, why don't you crack a few into that bowl?";
    // 记录发起制作的用户ID,避免其他人捣乱
    const initiatorId = message.author.id;

    // 构建按钮
    const eggsButton = new MessageButton()
        .setLabel("打鸡蛋!")
        .setStyle("blurple")
        // 如果你用的是旧版带按钮插件的discord.js v12,这里改回.setID("cupcakesStepOne")
        .setCustomId("cupcakesStepOne");

    // 发送初始消息
    // 旧版如果支持直接传按钮当第二个参数,可以按你原来的写法改
    const stepMessage = await message.channel.send({
        content: `${BASE_PROMPT} **0 / ${TOTAL_EGGS}**`,
        components: [{ type: 1, components: [eggsButton] }]
    });

    let currentEggs = 0;
    // 用当前消息的组件收集器代替全局监听,任务结束自动销毁,不会内存泄漏
    const buttonCollector = stepMessage.createMessageComponentCollector({
        filter: i => i.user.id === initiatorId && i.customId === "cupcakesStepOne",
        time: 300000 // 可选:加5分钟超时,超时自动结束任务避免一直占用资源
    });

    buttonCollector.on('collect', async button => {
        // 旧版这里改回 await button.reply.defer();
        await button.deferUpdate();
        currentEggs += 1;

        // 动态更新进度,不需要写多个if分支
        await stepMessage.edit(`${BASE_PROMPT} **${currentEggs} / ${TOTAL_EGGS}**`);

        // 达到目标后结束收集,禁用按钮
        if (currentEggs >= TOTAL_EGGS) {
            eggsButton.setDisabled(true);
            await stepMessage.edit({
                components: [{ type: 1, components: [eggsButton] }]
            });
            buttonCollector.stop('completed');
            // 这里可以直接加下一步的逻辑,比如触发加面粉的步骤
        }
    });

    // 可选:超时提示
    buttonCollector.on('end', (_, reason) => {
        if (reason !== 'completed') {
            eggsButton.setDisabled(true);
            stepMessage.edit({
                content: `${BASE_PROMPT} 操作超时已取消,请重新发起制作`,
                components: [{ type: 1, components: [eggsButton] }]
            });
        }
    });
}

优化点说明

  • 用消息组件收集器createMessageComponentCollector代替全局事件监听,只会监听当前这条消息的按钮点击,任务结束自动销毁监听,不会有内存泄漏问题
  • 增加了点击者校验,只有发起制作的玩家才能点击按钮,不会被其他人干扰
  • 所有可配置的常量都抽出来放在顶部,后续要改鸡蛋数量、提示语直接改常量就行,不用到处找代码
  • 动态拼接进度内容,删掉了冗余的嵌套if,代码逻辑更清晰
  • 进度达标后自动禁用按钮,避免无效点击,还加了可选的超时逻辑,避免任务一直挂着占用资源
  • 所有异步操作都加了await,避免异步报错

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 10:00:02