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

为什么我会收到“UnhandledPromiseRejectionWarning”?

为什么我会收到“UnhandledPromiseRejectionWarning”?

三国纷争 2021-06-29 05:12:20
我正在尝试调用异步方法。异步方法是:async connect() {        this.pool = await mysql.createPool(this.conf);        await this.pool.getConnection().catch((err) => { throw new Error(err) });}调用这个方法的代码是:(async () => {    await db.connect()        .catch((err) => {            console.error(`Database connection error: ${err.message}`);            throw new Error(err);        });})();但是,当 this.pool.getConnection() 中发生错误时,我收到以下警告:[Thu Jun 13 2019 23:10:59] [ERROR]  (node:18296) UnhandledPromiseRejectionWarning: Error: Error: Access denied for user 'root'@'localhost' (using password: YES)    at pool.getConnection.catch    at process._tickCallback[Thu Jun 13 2019 23:10:59] [ERROR]  (node:18296) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)[Thu Jun 13 2019 23:10:59] [ERROR]  (node:18296) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.阅读了类似问题的答案后,我明白必须处理来自 Promises 的拒绝,但是我不知道我没有正确处理这个问题的地方。this.pool.getConnection() 调用有一个 catch 块,在那里我抛出错误,所以它被传递给匿名调用函数来处理。我已经尝试了此代码的几种变体,包括向匿名函数本身添加一个 catch 块并在那里再次抛出错误,但似乎没有任何效果,并且警告总是源自 this.pool.getConnection() 调用。我试图实现的是将 connect() 方法中发生的任何错误传递给匿名函数进行处理。我哪里错了?提前致谢。编辑:有趣的是,如果我按如下方式编写 this.pool.getConnection() 行(catch 块中没有任何内容),警告就会消失:await this.pool.getConnection().catch((err) => {});当我尝试在箭头函数内执行任何操作时,例如将错误分配给变量,警告再次出现。
查看完整描述

2 回答

?
慕田峪7331174

TA贡献1828条经验 获得超13个赞

在此代码中,您没有处理错误:


(async () => {

    await db.connect()

        .catch((err) => {

            console.error(`Database connection error: ${err.message}`);

            throw new Error(err);

        });

})();

如果db.connect()拒绝,那么您的.catch()遗嘱将被调用并重新抛出。这意味着await db.connect()将看到一个被拒绝的承诺,你的包装异步函数将返回一个你没有处理程序的被拒绝的承诺。因此,您会收到未经处理的拒绝。


您可以使错误完全在您的async函数中处理,因此永远不会返回被拒绝的承诺,或者您可以正确处理错误。


仅供参考,await与.catch(). 通常你使用.then()and.catch()和awaitwith try/catch。


如果您想要的所有错误处理都是记录错误并避免警告,那么您可以更改为:


db.connect().catch((err) => {

    console.error(`Database connection error: ${err.message}`);

    // put any other required error handling here

});

通过删除throw err,您可以在本地“处理”错误,因此没有未处理的拒绝。你在这里唯一的拒绝被处理了。另外,请注意似乎不需要async或await因为您只是在进行函数调用并处理任何异常。


注意,设计模式:


async function foo() {

    await f();

}

几乎与以下相同:


function foo() {

    return f();

}

唯一不同的地方是如果f()没有返回承诺或同步抛出,这两种情况都不应该在行为正确的承诺返回 API 中发生。


因为我更喜欢最简单的代码表达式来实现你的目标,所以我宁愿不使用async/await它,除非它实际上可以帮助你使代码更简单。


查看完整回答
反对 回复 2021-07-01
?
森栏

TA贡献1810条经验 获得超5个赞

事实证明,虽然我的代码在任何方面都不理想,但问题的真正根源是我除了匿名函数之外还从其他地方调用 db.connect() 。另一个调用没有用于错误处理的 catch 块,因此是 UnhandledPromiseRejection 警告。一旦我删除了对 db.connect() 的重复调用,警告就消失了。


作为参考,这里是在评论/答案中的贡献者的帮助下改进的工作代码:


数据库类中的方法:


async connect() {

    this.pool = await mysql.createPool(this.conf);

    return await this.pool.getConnection();

}

以及对它的调用:


db.connect()

  .then(result => {

      console.log(result)

  })

  .catch(err => {

      console.error(`Database connection error: ${err.message}`);

  });


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

添加回答

举报

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