为了账号安全,请及时绑定邮箱和手机立即绑定

如何等待此功能完成?

如何等待此功能完成?

萧十郎 2022-07-21 22:30:33
在将数据发送到控制台之前,我需要等待映射功能完成。我知道这与 Promise 有关。我已经尝试了几个小时,即使在阅读了很多关于 Promise 和异步函数的内容之后,我也无法让它工作......async function inactiveMemberWarner() {    var msg = "```javascript\nI have sent warnings to members that have been inactive for 2 weeks.\n\n"    var inactiveMembers = '';    var count = 0;    var guildMembers = client.guilds.find(g => g.name === mainGuild).members;    const keyPromises = await guildMembers.map(async (member) => {        if (isMod(member)) {            connection.query(`SELECT * from users WHERE userID='${member.id}'`, (err, data) => {                if (data[0]) {                    if (!data[0].warnedForInactivity && moment().isSameOrAfter(moment(data[0].lastMSGDate).add('2', 'week'))) {                        count++;                        var updateWarning = {warnedForInactivity: 1}                        connection.query(`UPDATE users SET ? WHERE userID='${data[0].userID}'`, updateWarning);                        member.send(`**[*]** WARNING: You've been inactive on \`\`${mainGuild}\`\` for 2 weeks. Members that have been inactive for at least a month will be kicked.`);                        inactiveMembers += `${count}. ${member.user.tag}\n`;                        return inactiveMembers;                    }                }            });        }    });    await Promise.all(keyPromises).then(inactiveMembersData => console.log(inactiveMembers)); // RETURNS AN EMPTY STRING    setTimeout(() => console.log(inactiveMembers), 5000); // RETURNS THE INACTIVE MEMBERS AFTER WAITING FOR 5 SECONDS (PRMITIVE WAY)}inactiveMemberWarner();先感谢您!
查看完整描述

2 回答

?
aluckdog

TA贡献1847条经验 获得超7个赞

你很近,但不完全在那里。

首先,一些注意事项:

  • await可以用于任何值,但将它用于任何不是 Promise 的东西是完全没有意义的。你guildMembers.map(...);返回一个数组,而不是一个 Promise。

  • 混合await.then(...)工作,但有点混乱。您已经在使用await- 为什么还要处理回调?

  • 像这样使用guildMembers.map(async ...)将确保所有请求或多或少立即被触发,并且它们可以按任何顺序完成。这很好,但它是一种竞争条件,会导致或多或少随机的结果顺序。

  • 即使只是在概念上,这也不是一个好方法!每当您必须循环查询时,请尝试并研究仅在一个查询中执行此操作的方法。SQL 相当强大。

您当前的代码不起作用的原因是您的connection.query函数逃脱了异步控制流。我的意思是,使用 async/await 和 Promises 的全部意义基本上是在本地跟踪回调,并利用 Promise 链来动态添加回调。如果您调用返回 Promise 的异步函数,您现在可以在代码中的任何其他位置携带该 Promise 并动态地将成功处理程序附加到它:使用.then()或使用 sugar await

但是这个connection.query函数没有返回一个 Promise,它只是让你传递另一个裸回调——这个回调没有被 Promise 跟踪!Promise 没有对该回调的引用,它不知道何时调用该回调,因此您的 async/await 控制流被转义,并且您的 Promise 在查询运行之前很久就解决了。

你可以通过在 async 函数中创建一个新的 Promise 来解决这个问题:

async function inactiveMemberWarner() {

    var msg = "```javascript\nI have sent warnings to members that have been inactive for 2 weeks.\n\n"

    var inactiveMembers = '';

    var count = 0;

    var guildMembers = client.guilds.find(g => g.name === mainGuild).members;


    const keyPromises = guildMembers.map(async (member) => {

        if (isMod(member)) {

            return new Promise((resolve, reject) => {

                connection.query(`SELECT * from users WHERE userID='${member.id}'`, (err, data) => {

                    if (err) reject(err); //make errors bubble up so they can be handled

                    if (data[0]) {

                        if (!data[0].warnedForInactivity && moment().isSameOrAfter(moment(data[0].lastMSGDate).add('2', 'week'))) {

                            count++;

                            var updateWarning = {warnedForInactivity: 1}

                            connection.query(`UPDATE users SET ? WHERE userID='${data[0].userID}'`, updateWarning);

                            member.send(`**[*]** WARNING: You've been inactive on \`\`${mainGuild}\`\` for 2 weeks. Members that have been inactive for at least a month will be kicked.`);

                            resolve(`${count}. ${member.user.tag}\n`;);

                        }

                    } else resolve(""); //make sure to always resolve or the promise may hang

                });

            });

        }

    });


    let inactiveMembersData = await Promise.all(keyPromises); // Returns an array of inactive member snippets.

    inactiveMembers = inactiveMembersData.join(""); //join array of snippets into one string

}


inactiveMemberWarner();

这会起作用,但是有一个更好的方法。SQL 支持IN运算符,它允许您拥有类似WHERE userID IN (list_of_ids). 换句话说,您可以在一个查询中执行此操作。您甚至可以指定更多条件,例如warnedForInactivity = 0and lastMSGDate BETWEEN (NOW() - INTERVAL 14 DAY) AND NOW()。通过这种方式,您可以将所有当前的处理逻辑卸载到 SQL 服务器上——您几乎每次都应该尝试这样做。它也会大大简化这段代码。我不会再进一步了,因为它超出了这个问题的范围,但是如果您无法弄清楚,请随时问另一个。


查看完整回答
反对 回复 2022-07-21
?
拉丁的传说

TA贡献1789条经验 获得超8个赞

我无法对此进行测试,但这通常对我有用的是当想要等待 smt 时:


async function inactiveMemberWarner() {

    new Promise(function(cb,rj){

        var msg = "```javascript\nI have sent warnings to members that have been inactive for 2 weeks.\n\n"

        var inactiveMembers = '';

        var count = 0;

        var guildMembers = client.guilds.find(g => g.name === mainGuild).members;

        const keyPromises = await guildMembers.map(async (member) => {

            if (isMod(member)) {

                connection.query(`SELECT * from users WHERE userID='${member.id}'`, (err, data) => {

                    if (data[0]) {

                        if (!data[0].warnedForInactivity && moment().isSameOrAfter(moment(data[0].lastMSGDate).add('2', 'week'))) {

                            count++;

                            var updateWarning = {warnedForInactivity: 1}

                            connection.query(`UPDATE users SET ? WHERE userID='${data[0].userID}'`, updateWarning);

                            member.send(`**[*]** WARNING: You've been inactive on \`\`${mainGuild}\`\` for 2 weeks. Members that have been inactive for at least a month will be kicked.`);

                            inactiveMembers += `${count}. ${member.user.tag}\n`;

                            cb(inactiveMembers);

                        }

                    }

                });

            }

        });

        cb('No Members');

    }).then(inactiveMembersData => console.log(inactiveMembers)); // SHOULD RETURNS THE INACTIVE MEMBERS

}


inactiveMemberWarner();


查看完整回答
反对 回复 2022-07-21
  • 2 回答
  • 0 关注
  • 109 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信