Discord.js中setTimeout回调内message.reply方法不生效问题排查
俄罗斯轮盘Discord机器人setTimeout回调消息发送失败问题
问题描述
开发俄罗斯轮盘Discord机器人时遇到如下异常:
- setTimeout回调内的
message.reply("in setTimeout")调用无响应,不会在Discord频道返回消息 - 同位置的
console.log("in setTimeout")可以正常在终端打印内容
临时解决方法
通过修改Node.js老年代内存上限参数可以临时解决该问题,Windows PowerShell下执行命令:$env:NODE_OPTIONS="--max-old-space-size=8192"
问题根因
该问题本质是代码逻辑存在死循环,导致Node.js事件循环被阻塞,异步的Discord消息发送请求无法被调度执行,仅同步的控制台打印可以正常输出。
原问题代码如下:
setTimeout(() => { message.reply("in setTimeout") console.log("in setTimeout"); // 原意大利语含义:没人想玩吗? if (players.length < 1) return message.channel.send(`Nessuno vuole giocare? ):`); // 原意大利语含义:这是自杀...我喜欢但单人玩不算俄罗斯轮盘 if (players.length < 2) return message.channel.send(`Questo è suicidio... mi piace ma non è una roulette russa da soli`); let scelta = sixshooter[Math.floor(Math.random() * sixshooter.length)] let i = 0 while (i < players.length) { if (scelta == "unlucky bro ☠️") { players.splice(i, 1) } i++; // 当本轮没有玩家被淘汰时,i会被反复重置为0,循环永远不会终止,阻塞Node.js事件循环 if (i >= players.length) { i = 0 } message.channel.send(`${players[i]}, ${scelta}`) } }, 5000);
当本次随机结果scelta不为淘汰标识unlucky bro ☠️时,players数组长度不会发生变化,i到达数组末尾后会被重置为0,循环永远不会终止,占满主线程资源,所有异步任务都会被挂起。增大内存仅能延缓程序卡死时间,无法解决逻辑漏洞。
永久修复建议
将死循环逻辑改为按间隔轮询的实现,避免阻塞事件循环。如果要模拟逐轮开枪的效果,可以使用setInterval逐次执行玩家判断和消息发送,每轮执行完成后再进入下一轮,没有玩家剩余时清除定时器即可。
内容的提问来源于stack exchange,提问作者Heldin
相关产品推荐
相关产品推荐

