如何等待此功能完成?

Posted

技术标签:

【中文标题】如何等待此功能完成?【英文标题】:How to wait for this function to finish? 【发布时间】:2020-08-14 03:35:48 【问题描述】:

在将数据发送到控制台之前,我需要等待映射功能完成。我知道这与 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();

提前谢谢你!

【问题讨论】:

顺便说一句,您为什么要将文本消息格式化为 Javascript?这没有任何意义。 【参考方案1】:

我无法对此进行测试,但是当我想等待 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();

【讨论】:

【参考方案2】:

你已经很接近了,但还不够。

首先,一些注意事项:

await 可以用于任何值,但将它用于任何不是 Promise 的东西是完全没有意义的。您的 guildMembers.map(...); 返回一个 数组,而不是 Promise。 混合await.then(...) 可以,但有点混乱。您已经在使用 await - 为什么还要处理回调? 像这样使用guildMembers.map(async ...) 将确保所有请求或多或少地立即触发,并且它们可以按任何顺序完成。这很好,但它是一种竞争条件,会导致或多或少随机的结果顺序。 这不是一个好方法,即使只是在概念上!每当您必须循环查询时,请尝试并研究仅在一个查询中执行此操作的方法。 SQL 相当强大。

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

但是connection.query 函数没有返回一个 Promise,它只是让你传递另一个裸回调 - 这个回调没有被 Promise 跟踪! Promise 没有对该回调的引用,它不知道该回调何时被调用,因此您的 async/await 控制流被转义,并且您的 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 = 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 = 0lastMSGDate BETWEEN (NOW() - INTERVAL 14 DAY) AND NOW()。通过这种方式,您可以将所有当前处理逻辑卸载到 SQL 服务器上 - 您应该尝试每次都这样做。它也会大大简化这段代码。我不会再进一步​​了,因为它超出了这个问题的范围,但是如果您无法弄清楚,请随时询问其他人。

【讨论】:

感谢您的解释和代码!以后我一定会开始好好利用 SQL。

以上是关于如何等待此功能完成?的主要内容,如果未能解决你的问题,请参考以下文章

如何在开始下一个功能之前等待功能完成?

如何等待多个异步功能完成?

如何在一个请求中等待,直到另一个请求完成 nodeJS 中相同功能的执行

async/await 函数不等待。多个功能不按顺序运行和完成

等待所有 firebase 调用使用 map 函数完成

如何让 Python FastAPI 异步/等待功能正常工作?