将 setTimeout 包装在 Promise 中

问题描述 投票:0回答:1

我已经阅读了本网站上所有与此相关的类似问题,但似乎无法确切地弄清楚如何使 setTimeout 与我的用例的 Promise/await 一起工作。我使用的是discord.js v14,并且有一个斜杠命令可以添加角色30分钟。该命令有效,但有时机器人不会删除该角色。我认为这是因为 setTimeout 没有被承诺/等待,因此在等待的“member.roles.add(role.id)”之前运行。如何让 setTimeout 等待?

附注每个全局变量对应一个不同的命令,该命令将角色添加不同的时间(pug1Timeout = 1 小时等)。

const {
  CommandInteraction,
  PermissionsBitField,
  PermissionFlagsBits,
  SlashCommandBuilder,
  EmbedBuilder,
  ActionRowBuilder,
  Client,
  SelectMenuBuilder,
  ApplicationCommandOptionType,
  ChannelType,
} = require("discord.js");

//the pug queue commands reset the role timer to whatever the last used pug command time is

module.exports = {
  data: new SlashCommandBuilder()
    .setName("pug30")
    .setDescription("Adds the user to the PUG Queue for 30 minutes."),
  async execute(interaction) {
    const user = interaction.user.id;
    //is this supposed to be interaction.user?
    const role = interaction.guild.roles.cache.get("628292255785943065");
    const member = await interaction.guild.members.fetch(user);

    if (!member.roles.cache.has(role.id)) {
      member.roles.add(role.id);

      global.pug30Timeout = setTimeout(
        () => member.roles.remove(role.id),
        1800000,
      );

      //await new Promise(resolve => setTimeout(resolve, 1800000))

      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 });
    } else {
      clearTimeout(global.pug30Timeout);
      clearTimeout(global.pug1Timeout);
      clearTimeout(global.pug2Timeout);
      clearTimeout(global.pug3Timeout);
      clearTimeout(global.pug4Timeout);

      //if user has the role already and uses this command again, it resets the timer

      global.pug30Timeout = setTimeout(
        () => member.roles.remove(role.id),
        1800000,
      );

      //need to repeat global.pug1Timeout = ... here because if you use this command more than 2 times before the time runs out it only resets to the 2nd timer

      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 });
    }
  },
};
javascript discord.js
1个回答
0
投票

由于共享使用

global.pug30Timeout
,这看起来像是竞争条件。想想这个流程...

  1. 用户 #1 运行您的斜杠命令,角色被添加,计时器开始删除它。
  2. 用户 #2 运行您的命令,角色已添加,并且
    global.pug30Timeout
    现在指的是用户 #2 的删除计时器。但两个计时器仍在运行。
  3. 然后用户 #1 再次运行该命令。现在用户#2的计时器已被清除,并且
    global.pug30Timeout
    指的是用户#1的新删除计时器;此后,用户 #2 的角色永远不会被删除

将计时器存储在用户键入的地图中,以保持它们隔离。

const removalTimers = new Map();

module.exports = {
  // ...

  async execute(interaction) {
    const user = interaction.user.id;
    const role = interaction.guild.roles.cache.get('628292255785943065');
    const member = await interaction.guild.members.fetch(user);

    if (!member.roles.cache.has(role.id)) {
      member.roles.add(role.id);
    } else {
      clearTimeout(removalTimers.get(user));
    }

    removalTimers.set(
      user,
      setTimeout(() => {
        member.roles.remove(role.id);
      }, 1800000),
    );

    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 });
  },
};
© www.soinside.com 2019 - 2024. All rights reserved.