You need to enable JavaScript to run this app. Discord.js 命令处理器配置的统一冷却无报错也不生效问题
优惠活动
大模型
产品
解决方案
定价
更多

Discord.js 命令处理器配置的统一冷却无报错也不生效问题

Discord.js 统一命令冷却功能失效修复方案

问题现状

  • 需求:在消息事件处理器中实现全局统一冷却逻辑,无需在单个命令文件中重复编写冷却判断代码
  • 异常表现:冷却逻辑运行无任何控制台报错,但连续触发命令完全不会被拦截,也不会弹出冷却提示

现有问题代码

消息事件处理器中的冷却实现

const args = message.content.slice(prefix.length).trim().split(/ +/g);
const cmd = args.shift().toLowerCase();
let command = client.commands.get(cmd);
//cooldowns
    const cooldowns = new Discord.Collection();
    if (!cooldowns.has(command.name)) {
        cooldowns.set(command.name, new Discord.Collection());
    }
    const now = Date.now();
    const timestamps = cooldowns.get(command.name);
    const cooldownAmount = (command.cooldown || 3) * 1000;

    if (timestamps.has(message.author.id)) {
        const expirationTime = timestamps.get(message.author.id) + cooldownAmount;
        if (now < expirationTime) {
            const timeLeft = (expirationTime - now) / 1000;
            return message.reply(`please wait ${timeLeft.toFixed(1)} more second(s) before reusing the \`${command.name}\` command.`);
        }
    }
    
    timestamps.set(message.author.id, now);
    setTimeout(() => timestamps.delete(message.author.id), cooldownAmount);
    //cooldowns

对应命令文件配置

module.exports = {
    name: 'tag',
    aliases: ['tags', 't'],
    cooldown: 5,
    category: 'fun',
    description: 'Create a custom command',
    usage: `tag create|delete|edit`,
    run: (client, message, args) => {
        return message.reply('test, command is not done yet this is to test the cooldown')
    }
}

失效核心原因

全局冷却状态集合的作用域错误:cooldowns集合被定义在消息事件的回调函数内部,每次收到新消息触发事件时,回调都会重新执行,生成一个全新的空cooldowns集合,上一次触发命令时存储的用户时间戳会被直接清空,根本无法跨消息事件留存状态,自然永远走不到冷却拦截的分支。
另外这段代码缺少基础边界判断:如果用户输入的是不存在的命令,直接访问command.name会触发报错,只是大概率前面已经加了非空判断才没暴露这个问题。

修复后的可运行实现

  1. 把cooldowns集合的初始化移到bot启动阶段,挂在客户端实例上,保证整个程序运行周期内只初始化一次,状态可跨事件留存
  2. 补全命令非空、机器人消息拦截的基础判断
  3. 冷却判断逻辑放在命令执行流程之前,只有通过校验的请求才能进入命令执行
// 在bot初始化阶段、绑定消息事件之前,全局初始化冷却集合
client.cooldowns = new Discord.Collection();

client.on('messageCreate', message => {
    // 前缀、命令解析逻辑保持原有逻辑
    const args = message.content.slice(prefix.length).trim().split(/ +/g);
    const cmd = args.shift().toLowerCase();
    // 兼容命令别名查找
    let command = client.commands.get(cmd) || client.aliases.get(cmd);

    // 边界校验:命令不存在、消息来自机器人时直接返回
    if (!command || message.author.bot) return;

    // 全局冷却判断逻辑
    if (!client.cooldowns.has(command.name)) {
        client.cooldowns.set(command.name, new Discord.Collection());
    }
    const now = Date.now();
    const timestamps = client.cooldowns.get(command.name);
    // 命令未配置冷却时间时默认3秒
    const cooldownAmount = (command.cooldown || 3) * 1000;

    if (timestamps.has(message.author.id)) {
        const expirationTime = timestamps.get(message.author.id) + cooldownAmount;
        if (now < expirationTime) {
            const timeLeft = (expirationTime - now) / 1000;
            return message.reply(`请等待 ${timeLeft.toFixed(1)} 秒后再使用 \`${command.name}\` 命令。`);
        }
    }
    
    timestamps.set(message.author.id, now);
    setTimeout(() => timestamps.delete(message.author.id), cooldownAmount);

    // 冷却校验通过后,执行命令逻辑
    command.run(client, message, args);
})

注意事项

  • 冷却集合绝对不能定义在高频执行的回调作用域内,否则永远无法留存状态
  • 命令查找逻辑要同步适配别名,避免用别名触发命令时冷却规则失效
  • 冷却判断要放在命令执行之前,避免未通过校验的请求直接触发命令逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.06 08:54:04