【问题标题】:Finally block execute before the end of try blockfinally 块在 try 块结束之前执行
【发布时间】:2021-05-13 15:52:40
【问题描述】:

上下文:

我有一个在 discord.js 上运行的 discord 机器人,我最近创建了一个 MongoDB 数据库来存储一些我可以在未来某个时候使用的元素。 我想检索特定不和谐“公会”的所有成员并将它们放入单独的 MongoDB 文档中。

我的工作:

首先,我使用 :

获取这些成员
const members = await testGuild.members.fetch();

这会返回一个“Discord.Collection”对象,它本质上是一个 Map 对象。

然后我使用 mongoose 连接到我的 MongoDB,并使用以下方法为成员集合的每个成员创建一个新文档:

await mongo().then(async mongoose => {
        try {
            members.each(async member => {
                const {user} = member
                await discordUserSchema.findOneAndUpdate({
                    _id: user.id
                }, {
                    _id: user.id,
                    username: user.username,
                    discriminator: user.discriminator,
                    avatar: user.avatar,
                    bot: user.bot
                }, {
                    upsert: true
                });
            });
        } finally {
            mongoose.connection.close();
        }
    });

我的问题是 finally 块在我的 try 块完成之前执行,我收到此错误:

(node:25008) UnhandledPromiseRejectionWarning: MongoError: server is closed

如果我删除 try/finally 块,我没有任何错误,并且文档已正确添加到我的集合中,但这不是正确的方法...

我还尝试在每个循环内部连接到我的数据库,但这很糟糕,因为它打开然后关闭我添加到集合中的每个成员的连接,最终,我收到超时错误。

我在这里错过了什么?为什么 finally 块会很快执行?那是因为我的循环中的异步函数吗?我该如何以不同的方式处理?

谢谢。

【问题讨论】:

  • 尝试await Promise.all(members.each(async ... 等待,假设.each 返回承诺数组......它可能不会。如果存在,您可能需要更像members.map 的东西。无论如何,您需要以一种或另一种方式等待所有这些承诺。
  • @David784 await Promise.all 在这种情况下无济于事。不是Array.prototype.map
  • @David784 谢谢!你把我放在正确的轨道上,然后 AlexZeDim 给了我完整的答案!祝你有美好的一天!

标签: javascript node.js mongodb mongoose discord.js


【解决方案1】:

问题在于discord.js.each 函数,它是.forEach 的副本,不会等待,例如,您可能会看到a relevant case in this question

所以,要解决try/catch/finally 和同步代码的问题,您需要使用:

for (const member of members) {
  /** 
   * your async/await logic
   * if you want it one by one
   */
}

await Promise.all(members.map(async member => {
  /** 
   * await logic here 
   * if you want all at once in parallel
   */
}));

如前所述。如果您的应用程序在开始时只创建一次与 MongoDB 的连接,请不要在每次需要数据库中的某些内容时打开/关闭新的连接,只需使用旧的连接即可。

【讨论】:

  • 好的,谢谢先生!这正是我需要的解释。我选择了第二个选项,现在一切都很好。祝你有美好的一天!
【解决方案2】:

This article 会帮助你。 TLDR;不要在.then() 中使用try catch,只需使用catchfinally 已经可以与.then() 一起使用

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-27
    • 2015-01-22
    • 1970-01-01
    • 2017-07-20
    相关资源
    最近更新 更多