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

discord.js v14中如何让setTimeout支持await等待?

解决discord.js v14中角色自动移除失效与setTimeout/Promise结合问题

你的代码出现角色偶尔未自动移除的问题,主要有两个核心原因:

  1. member.roles.add() 是异步操作,未使用 await 等待完成,极端情况下可能出现角色还未添加成功就设置了移除定时器;
  2. 全局变量存储定时器导致多用户冲突:多个用户使用同一命令时,后执行的用户会覆盖全局定时器变量,导致前一个用户的定时器被清除,角色无法自动移除。

下面是针对性的解决方案:

1. 封装可await的延迟函数

先实现一个Promise化的延迟工具函数,方便后续异步场景使用:

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

2. 替换全局变量,为每个用户独立管理定时器

用Map对象替代全局变量,关联用户ID与对应的定时器ID,确保每个用户的定时器互不干扰:

// 存储用户ID到定时器ID的映射
const userTimers = new Map();
// 统一管理各命令的延迟时长(毫秒)
const commandDelayMap = {
  pug30: 1800000, // 30分钟
  pug1: 3600000,  // 1小时
  pug2: 7200000,  // 2小时
  pug3: 10800000, // 3小时
  pug4: 14400000  // 4小时
};

3. 修改命令执行逻辑

调整代码,确保异步操作都用await,并通过Map管理定时器:

const { SlashCommandBuilder, EmbedBuilder } = require("discord.js");

const userTimers = new Map();
const commandDelayMap = {
  pug30: 1800000,
  pug1: 3600000,
  pug2: 7200000,
  pug3: 10800000,
  pug4: 14400000
};

function delay(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

module.exports = {
  data: new SlashCommandBuilder()
    .setName("pug30")
    .setDescription("Adds the user to the PUG Queue for 30 minutes."),
  async execute(interaction) {
    const userId = interaction.user.id;
    const role = interaction.guild.roles.cache.get("628292255785943065");
    const member = await interaction.guild.members.fetch(userId);
    const currentCmd = "pug30";
    const delayMs = commandDelayMap[currentCmd];

    // 清除该用户之前的所有定时器(不管是哪个命令的)
    if (userTimers.has(userId)) {
      clearTimeout(userTimers.get(userId));
      userTimers.delete(userId);
    }

    // 确保角色添加完成
    if (!member.roles.cache.has(role.id)) {
      await member.roles.add(role.id);
    }

    // 设置新的延迟移除任务
    const timerId = setTimeout(async () => {
      try {
        await member.roles.remove(role.id);
        userTimers.delete(userId);
      } catch (err) {
        console.error(`移除用户${userId}的PUG角色失败:`, err);
      }
    }, delayMs);

    // 保存当前用户的定时器ID
    userTimers.set(userId, timerId);

    // 即时回复用户
    const embed = new EmbedBuilder()
      .setTitle(" ")
      .setDescription(`Added ${interaction.user} to the PUG Queue for 30 minutes.`)
      .setColor(0x4169e1);
    await interaction.reply({ embeds: [embed], ephemeral: false });
  },
};

关键改进说明

  • 用户独立定时器:通过userTimers Map存储每个用户的定时器,彻底解决多用户冲突问题;
  • 异步操作await:member.roles.add()和member.roles.remove()都添加await,确保角色操作完成后再执行后续逻辑;
  • 统一重置定时器:用户再次执行命令时,先清除之前的定时器,再设置新的,保证计时正确重置;
  • 错误处理:移除角色时加入try/catch,避免因权限不足、用户退出服务器等情况导致报错。

关于await setTimeout的注意事项

不要在命令的execute函数中直接await delay(1800000),这会阻塞命令回复,用户需要等待30分钟才能收到反馈。正确的方式是将延迟移除逻辑放在独立的异步任务中(如上述代码的setTimeout封装),既实现定时功能,又不影响命令的即时响应。

内容的提问来源于stack exchange,提问作者Mythic-ctrl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 15:04:51