Discord.js在while循环中监听按钮事件单次触发多次回调问题
问题原因
你的同步while循环不会等待按钮交互触发就会立即执行完毕,代码运行时会在极短时间内完成5次循环,给同一条发送的消息绑定了5个独立的按钮交互收集器。当你按下一次按钮时,5个收集器会同时监听到交互事件,因此会打印5次pong,完全不符合你预期的「每次交互后再进入下一轮循环」的逻辑。
修复代码
let sentMessage = await message.channel.send({ content: "press a button" , components: [ new MessageActionRow() .addComponents( new MessageButton().setCustomId("yamete").setLabel("yamete").setStyle("PRIMARY") ) ] }) // 直接配置收集器的最大收集次数和超时时间,无需手动写循环 const inputCollector = sentMessage.createMessageComponentCollector({ componentType: "BUTTON", time: ms("10 seconds"), max: 5 // 最多响应5次交互 }) inputCollector.on("collect", async input => { // 先处理交互回执,避免按钮超时报错 await input.deferUpdate() console.log("pong") if (Math.floor(Math.random() * 1000) % 2 !== 0) { await sentMessage.edit({ content: "press the button again!", components: [ new MessageActionRow() .addComponents( new MessageButton().setCustomId("yamete").setLabel("yamete").setStyle("PRIMARY") ) ] }) } else { // 随机结果为假时直接终止收集器即可 inputCollector.stop("manual_end") } }) // 收集器结束时统一处理最终状态,触发场景包括:达到最大次数、超时、主动终止 inputCollector.on("end", () => { sentMessage.edit({ content: "dont press the button", components: [] }) })
逻辑说明
- 直接通过收集器的
max参数限制最多响应5次交互,无需手动编写同步循环 - 每次收到交互后先调用
deferUpdate避免Discord判定按钮交互超时 - 不需要继续接收交互时直接调用收集器的
stop方法即可终止监听 - 收集器的
end事件统一处理最终消息状态,避免多处重复编写编辑逻辑
内容的提问来源于stack exchange,提问作者lowfi 2
相关产品推荐
相关产品推荐

