我已经阅读了本网站上所有与此相关的类似问题,但似乎无法确切地弄清楚如何使 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 });
}
},
};
由于共享使用
global.pug30Timeout
,这看起来像是竞争条件。想想这个流程...
global.pug30Timeout
现在指的是用户 #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 });
},
};