簡體   English   中英

如何等待這個 function 完成?

[英]How to wait for this function to finish?

在將數據發送到控制台之前,我需要等待映射 function 完成。 我知道它與 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();

先感謝您!

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

首先,一些注意事項:

  • await可以用於任何值,但將它用於任何不是 Promise 的值是完全沒有意義的。 你的guildMembers.map(...); 返回一個數組,而不是 Promise。
  • 混合await.then(...)有效,但有點混亂。 您已經在使用await - 為什么還要處理回調?
  • 像這樣使用guildMembers.map(async...)將確保所有請求或多或少立即被觸發,並且它們可以以任何順序完成。 這很好,但它是一種競爭條件,會導致或多或少隨機的結果順序。
  • 即使只是在概念上,這也不是一個好方法,任何時候你都必須循環查詢。 嘗試並調查僅在一個查詢中執行此操作的方法。 SQL 相當強大。

您當前的代碼不起作用的原因是您的connection.query function逃脫了異步控制流 我的意思是,使用 async/await 和 Promises 的全部目的基本上是在本地跟蹤回調,並利用 promise 鏈接來動態添加回調。 如果您調用異步 function 並返回 Promise,您現在可以在代碼中的任何其他位置攜帶該await並動態附加成功處理程序.then()

But the connection.query function doesn't return a Promise, it just has you pass another naked callback - this one is not being tracked by a Promise, The Promise doesn't have a reference to that callback, it can't know when該回調被調用。 因此,您的 async/await 控制流被轉義,並且您的承諾在查詢運行之前很久就解決了。

您可以通過在異步 function 中創建新的 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 服務器上——您幾乎每次都應該嘗試這樣做。 它也會大大簡化這段代碼。 我不會再做 go 了,因為這個問題已經超出了 scope 的范圍,但如果你想不明白,請隨時問另一個。

我無法對此進行測試,但這通常對我有用的是當想要等待 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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM