使用Node.js实现支持多实例的异步倒计时器 适配Discord机器人自动断连需求
实现方案
核心原理
Node.js 的异步事件循环原生支持多定时器并行,不需要你自己写每秒减计数的循环,这种实现既浪费性能也容易出问题。内置的 setTimeout 方法本身就是非阻塞的,同时创建成百上千个定时器实例都不会互相干扰,完全满足多用户同时触发sleepcall指令的需求。
基础实现方案
直接使用 setTimeout 实现(最推荐)
这种方案最简单,还支持后续手动取消定时的需求:
// 存储所有定时器实例,方便用户主动取消定时、或重复提交指令时覆盖旧定时 const sleepCallTimers = new Map() /** * 启动睡眠通话断连定时 * @param {number} userId 用户ID * @param {number} timeoutSeconds 等待时长,单位秒 */ function startSleepCallTimer(userId, timeoutSeconds) { // 如果用户已有正在运行的定时,先清除旧的 if (sleepCallTimers.has(userId)) { clearTimeout(sleepCallTimers.get(userId)) } // 创建新定时器,时间到后执行断连逻辑 const timer = setTimeout(() => { // 这里调用你已经实现好的「将用户踢出语音频道」的逻辑 disconnectUserFromVC(userId) // 执行完成后清除存储的定时器记录 sleepCallTimers.delete(userId) }, timeoutSeconds * 1000) // setTimeout单位是毫秒,所以要乘1000转换单位 // 存储定时器实例 sleepCallTimers.set(userId, timer) } // 可选:实现取消定时的功能,适配用户主动取消、中途自行退出语音频道的场景 function cancelSleepCallTimer(userId) { if (sleepCallTimers.has(userId)) { clearTimeout(sleepCallTimers.get(userId)) sleepCallTimers.delete(userId) return true } return false }
async/await 语法版本
如果你偏好异步函数的写法,可以封装一个通用的等待工具函数:
// 封装等待指定时长的异步工具 function wait(seconds) { return new Promise(resolve => setTimeout(resolve, seconds * 1000)) } // 异步函数实现 async function sleepCallDisconnect(userId, timeoutSeconds) { await wait(timeoutSeconds) disconnectUserFromVC(userId) }
调用时直接执行sleepCallDisconnect(12345678, 3600)即可,多个调用同时触发也不会互相阻塞,await会主动让出线程,不会影响机器人响应其他指令。
注意事项
- 你使用的 Node.js 16.9.0 完全支持上述所有语法,不需要额外安装依赖
- 如果需要机器人重启后仍保留未触发的定时任务,还是需要将定时记录存储在SQL数据库中,机器人启动时读取剩余时间重新创建定时器即可;如果机器人不需要重启,纯内存存储定时器就可以正常运行
- 不要使用你伪代码中写的每秒减1的循环实现,Node.js是单线程模型,同步等待会直接卡住整个机器人的所有功能,必须使用内置的异步定时器
内容的提问来源于stack exchange,提问作者jimhub
相关产品推荐
相关产品推荐

