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

Discord.js V14监听无法停止问题求助

问题核心

你遇到的重复发送验证提示问题,本质是DM消息收集器未被彻底终止,且事件监听重复触发——用户多次点击按钮或旧收集器未清理时,多个收集器同时监听用户DM,导致一次回复触发多个逻辑分支。另外dmCollector.off('collect')仅移除事件监听,并未终止收集器运行,所以无法解决问题。

修复方案

1. 改用once绑定收集事件

验证码只需要用户回复一次,用once替代on,触发一次后自动移除监听,从根源避免重复响应:

// 替换原有的dmCollector.on('collect', ...)
dmCollector.once('collect', async m => {
  if (m.content === captcha) {
    await dmChannel.send('You have been verified!');
    await i.member.roles.add(newVerifiedRole);
    await i.member.roles.remove(newUnverifiedRole);
    dmCollector.stop('success'); // 主动终止收集器
  } else {
    await dmChannel.send('Incorrect captcha. Please try again.');
    dmCollector.stop('failure');
  }
});

2. 禁用按钮防止重复点击

用户快速多次点击按钮会创建多个并行的验证流程,导致多个收集器同时监听DM。处理按钮点击时先禁用按钮,完成后再恢复:

collector.on('collect', async i => {
  try {
    // 先禁用按钮,阻止重复点击
    await i.deferUpdate();
    row.components[0].setDisabled(true);
    await message.edit({ components: [row] });

    // ... 原有验证逻辑 ...

  } catch (error) {
    console.error(error);
  } finally {
    // 处理完成后恢复按钮可用
    row.components[0].setDisabled(false);
    await message.edit({ components: [row] });
  }
});

完整修复代码

// Listen for button click
const filter = i => i.customId === 'verification:start' && i.user.id === interaction.user.id;
const collector = message.createMessageComponentCollector(filter, { time: 30000 });

collector.on('collect', async i => {
  try {
    // 禁用按钮防止重复触发
    await i.deferUpdate();
    row.components[0].setDisabled(true);
    await message.edit({ components: [row] });

    // Check if user has already been verified
    if (i.member.roles.cache.has(newVerifiedRole)) {
      await i.user.send('You have already been verified!');
      return;
    }

    // Send captcha to user's DMs
    const dmChannel = await i.user.createDM();
    const captcha = generateCaptcha();
    await dmChannel.send(`Please enter the following captcha within 30 seconds: **${captcha}**`);
    const dmFilter = m => m.author.id === i.user.id;
    const dmCollector = dmChannel.createMessageCollector(dmFilter, { max: 1, time: 30000 });

    // 用once替代on,确保只触发一次
    dmCollector.once('collect', async m => {
      if (m.content === captcha) {
        await dmChannel.send('You have been verified!');
        await i.member.roles.add(newVerifiedRole);
        await i.member.roles.remove(newUnverifiedRole);
        dmCollector.stop('verified');
      } else {
        await dmChannel.send('Incorrect captcha. Please try again.');
        dmCollector.stop('wrong_captcha');
      }
    });

    dmCollector.on('end', async collected => {
      try {
        if (collected.size === 0) {
          await dmChannel.send('Time is up. Please try again.');
        }
      } catch (err) {
        console.error(`Error updating DM: ${err}`);
      }
    });
  } catch (error) {
    console.error(error);
    await i.user.send('An error occurred during verification. Please try again later.');
  } finally {
    // 恢复按钮状态
    row.components[0].setDisabled(false);
    await message.edit({ components: [row] });
  }
});

关键说明

  • once绑定的事件仅触发一次,触发后自动解绑,避免旧收集器干扰新的验证流程。
  • dmCollector.stop()会彻底终止收集器,停止监听并触发end事件,确保没有残留的监听逻辑。
  • 按钮禁用逻辑直接阻断了重复创建收集器的可能,是解决重复提示的关键一步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 00:45:49