discord.js - Discord poll bot async issues
问题描述
I am trying to make a poll command for a discord bot in which the user chooses a number of options in the first command (ie '!poll 4') and then chooses the questions and the options. I am having some issues getting the bot to wait for a response before it moves on to the next option in the loop. When I try and use await in the loop it says I cannot use await because it's not an async function, but it is an async function I think. I am very inexperienced with this so I am sure it is a simple error or probably multiple. If anyone can give me advice on a way to make the loop work as intended and ask for each option I would appreciate it. Also is there a way to add if statements to do addFields to an embed? Here is my code:
const Discord = module.require('discord.js');
module.exports = {
name: 'poll',
async execute(message, args) {
function isNumber(n) { return !isNaN(parseFloat(n)) && !isNaN(n - 0) }
if(isNumber(args[1])){
if(args[1]<2) return message.channel.send('Please choose a higher number of options for the poll :)');
if(args[1]>10) return message.channel.send('Please choose a lower number of options for the poll :)');
const filter = response => {
if(!response.author.bot) return response;
};
var question;
var options;
message.channel.send('What question would you like to ask?').then(() => {
message.channel.awaitMessages(filter, { max: 1, time: 15000})
.then(collected => {
question = `${collected.first()}?`;
message.channel.send('Question: ' + question);
for (var i = 0; i < args[1]; i++) {
message.channel.send('What is option ' + (i + 1) + '?').then(() => {
message.channel.awaitMessages(filter, { max: 1, time: 15000})
.then(collected => {
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
})
.catch(collected => {
message.channel.send('Poll has timed out.');
});
})
}
})
.catch(collected => {
message.channel.send('Poll has timed out.');
});
const embed = new Discord.MessageEmbed()
.setColor(3447003)
.setTitle(question)
.setDescription('choose an option')
/*
if (options[0]) .addField('1️⃣:' + option[0])
if (options[1]) .addField('2️⃣:' + option[1])
if (options[2]) .addField('3️⃣:' + option[2])
if (options[3]) .addField('4️⃣:' + option[3])
if (options[4]) .addField('5️⃣:' + option[4])
if (options[5]) .addField('6️⃣:' + option[5])
if (options[6]) .addField('7️⃣:' + option[6])
if (options[7]) .addField('8️⃣:' + option[7])
if (options[8]) .addField('9️⃣:' + option[8])
if (options[9]) .addField(':' + option[9])
*/
message.channel.send(embed).then(embedMessage => {
if (options[0]) embedMessage.react('1️⃣');
if (options[1]) embedMessage.react('2️⃣');
if (options[2]) embedMessage.react('3️⃣');
if (options[3]) embedMessage.react('4️⃣');
if (options[4]) embedMessage.react('5️⃣');
if (options[5]) embedMessage.react('6️⃣');
if (options[6]) embedMessage.react('7️⃣');
if (options[7]) embedMessage.react('8️⃣');
if (options[8]) embedMessage.react('9️⃣');
if (options[9]) embedMessage.react('');
});
});
}
}
}
解决方案
既然你说你试图await
在你的循环中使用,让我从你的代码片段中取出它包含的函数,稍微格式化一下,然后尝试做一些解释。免责声明:我不是专家,所以我也在学习。
.then(collected => {
question = `${collected.first()}?`;
message.channel.send(`Question: ${question}`);
for (var i = 0; i < args[1]; i++) {
message.channel.send(
`What is option ${i + 1}?`
).then(() => {
message.channel.awaitMessages(filter, {
"max": 1,
"time": 15000,
}).then(collected => {
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
}).catch(collected => {
message.channel.send("Poll has timed out.");
});
});
}
});
但在此之前,由于第一个内部.then()
仍然返回 a Promise
,您可以在外部范围内链接第二个内部.then()
以避免嵌套太深,并.catch()
在最后留下一个。关于这一点,将 catch 的参数称为error
. 所以这是新的片段:
.then(collected => {
question = `${collected.first()}?`;
message.channel.send('Question: ' + question);
for (var i = 0; i < args[1]; i++) {
message.channel.send(
`What is option ${i + 1}?`
).then(() => {
message.channel.awaitMessages(filter, {
"max": 1,
"time": 15000,
});
}).then(collected => { // Change .then() chaining
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
}).catch(error => { // Change parameter name
message.channel.send("Poll has timed out.");
});
}
})
现在发生的情况是每次迭代都立即一个接一个地运行。你.send()
有一大堆消息,每个都返回一个Promise
,然后Promise
,你传递一个回调函数.then()
,一旦每个Promise
解析成一个Message
. 该回调隐式返回 的结果.awaitMessages()
,这也是一个承诺,一旦解决,下一个回调中的下一个回调.then()
将使用前一个承诺解决的值作为参数传入,依此类推。
好的,所以您希望整个 Promise 链在进行下一次迭代之前完成处理和解析,对吗?您可以使用await
关键字暂停相关匿名函数的进度,直到其相关的基于承诺的操作解决或拒绝。问题是该函数必须用async
关键字标记,并且在您的代码中,实际上并非如此,您只是在使用Promise
s 和回调函数(关于“但我认为它是一个异步函数”)。因此,让我们添加上述两个关键字:
.then(async collected => { // Mark as async
question = `${collected.first()}?`;
message.channel.send('Question: ' + question);
for (var i = 0; i < args[1]; i++) {
await message.channel.send( // Wait for this entire Promise chain to resolve before proceeding
`What is option ${i + 1}?`
).then(() => {
message.channel.awaitMessages(filter, {
"max": 1,
"time": 15000,
});
}).then(collected => {
options[i] = collected.first;
message.channel.send(`Option ${i}: ${options[i]}`);
}).catch(error => {
message.channel.send("Poll has timed out.");
});
}
})
这应该会导致您想要的行为,尽管我的编辑可能有语法错误,因为我自己没有运行它。如果我有什么问题,请发表评论。
你可以在这里阅读更多:
推荐阅读
- sql - 修剪尾随零
- r - 如何使用用户输入的数字作为变量?
- c++ - 无法为自定义矢量类绑定 ostream 1value - C++
- javascript - 如何从 Angular 或任何其他网络平台获取 Firebase 安全数据
- java - 启动 Spring Boot Web 应用程序时出现 BeanCreationException
- c - 使用 readdir 在 for 循环中并行递归
- python - RuntimeError: stack 期望每个张量大小相等,但在条目 0 处得到 [32, 1],在条目 1 处得到 [32, 0]
- python - 如何将数字添加到列表中的所有整数(python)
- angular - 向现有工作箱工作人员注册 Firebase 服务工作人员
- batch-file - 批处理:二进制字符的按位异或不起作用