Discord民意调查机器人异步问题

时间:2020-07-12 22:33:09

标签: discord.js

我正在尝试为不和谐的机器人发出轮询命令,其中用户在第一个命令中选择多个选项(即“!poll 4”),然后选择问题和选项。我在让机器人等待响应之前遇到了一些问题,该机器人将继续前进到循环中的下一个选项。当我尝试在循环中使用await时,它说我不能使用await,因为它不是异步函数,但我认为它是异步函数。我对此没有经验,所以我确定这是一个简单的错误或可能是多个错误。如果有人可以给我一些建议,使循环按预期方式工作,并要求每个选项,我将不胜感激。还有一种方法可以添加if语句来为嵌入添加addFields?这是我的代码:

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('?');
                });
            });
        }
    }
}

1 个答案:

答案 0 :(得分:0)

由于您说过要在循环中使用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()仍返回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关键字来暂停相关匿名函数的进度,直到其关联的基于promise的操作得以解决或拒绝为止。问题是该函数必须用async关键字标记,而在您的代码中,实际上并非如此,您只是在使用Promise和回调函数(关于“但是我认为这是一个异步功能”)。因此,让我们添加上述两个关键字:

.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.");
        });
    }
})

这应该会导致您期望的行为,尽管我自己没有运行它,但是我的编辑可能存在语法错误。如果我做错了,请发表评论。

您可以在此处阅读更多信息: