Discord.js v14:多同时交互处理最佳实践方案咨询
Discord.js v14 多同时交互处理方案
1. 用交互ID精准跟踪处理状态(替代全局标记)
全局标记会粗暴拦截所有同命令请求,改用interaction.id(每个交互唯一)作为标识,用Map存储处理状态,能精准区分不同请求:
const processingInteractions = new Map(); async function handleLongRunningCommand(interaction) { // 检查当前交互是否正在处理 if (processingInteractions.has(interaction.id)) { await interaction.reply({ content: "该请求正在处理,请稍候!", ephemeral: true }); return; } processingInteractions.set(interaction.id, true); try { // 先发送延迟回复,避免Discord 3秒超时限制 await interaction.deferReply(); // 执行耗时业务逻辑 await longRunningDataProcess(); // 更新回复结果 await interaction.editReply("处理完成!"); } catch (error) { // 异常时也要更新回复告知用户 await interaction.editReply(`处理失败:${error.message}`); } finally { // 无论成功失败,都清理当前交互的处理标记 processingInteractions.delete(interaction.id); } }
2. 强制优先调用deferReply
耗时命令必然超过Discord要求的3秒回复时限,第一步必须调用interaction.deferReply(),让Discord先返回"正在处理"的占位消息,后续通过editReply更新内容,从根源避免上下文丢失问题。
3. 给用户-命令组合加限流(可选)
如果要防止同一用户短时间内重复触发同一耗时命令,可将用户ID+命令名作为key做冷却控制:
const userCommandCooldowns = new Map(); async function handleLongRunningCommand(interaction) { const key = `${interaction.user.id}-${interaction.commandName}`; const cooldown = 10000; // 10秒冷却时间 const lastTriggerTime = userCommandCooldowns.get(key); if (lastTriggerTime && Date.now() - lastTriggerTime < cooldown) { const remaining = Math.ceil((cooldown - (Date.now() - lastTriggerTime)) / 1000); await interaction.reply({ content: `请再等${remaining}秒后重试!`, ephemeral: true }); return; } userCommandCooldowns.set(key, Date.now()); try { await interaction.deferReply(); await longRunningDataProcess(); await interaction.editReply("处理完成!"); } catch (error) { await interaction.editReply(`处理失败:${error.message}`); } finally { // 冷却时间到后清理记录 setTimeout(() => userCommandCooldowns.delete(key), cooldown); } }
4. 全覆盖异常捕获与状态清理
确保所有异步操作都包裹在try/catch中,且在finally块里强制清理处理标记,避免因异常导致标记残留,影响后续请求。
5. 处理共享资源的竞态问题(可选)
如果耗时任务涉及共享资源(如数据库写操作),可通过队列实现串行处理,避免并发冲突:
const taskQueue = []; let isProcessing = false; async function processQueue() { if (isProcessing) return; isProcessing = true; while (taskQueue.length > 0) { const task = taskQueue.shift(); try { await task(); } catch (err) { console.error("任务执行失败:", err); } } isProcessing = false; } async function handleLongRunningCommand(interaction) { await interaction.deferReply(); // 将耗时任务加入队列 taskQueue.push(async () => { await longRunningDataProcess(); await interaction.editReply("处理完成!"); }); await processQueue(); }
内容的提问来源于stack exchange,提问作者Rich Humphreys
相关产品推荐
相关产品推荐

