2 回答

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 服務器上——您幾乎每次都應該嘗試這樣做。它也會大大簡化這段代碼。我不會再進一步了,因為它超出了這個問題的范圍,但是如果您無法弄清楚,請隨時問另一個。

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();
添加回答
舉報