【问题标题】:UnhandledPromiseRejectionWarning on async await promise异步等待承诺上的 UnhandledPromiseRejectionWarning
【发布时间】:2019-03-19 13:18:33
【问题描述】:

UnhandledPromiseRejectionWarning 异步等待承诺

我有这个代码:

function foo() {
  return new Promise((resolve, reject) => {
    db.foo.findOne({}, (err, docs) => {
      if (err || !docs) return reject();
      return resolve();
    });
  });
}

async function foobar() {
  await foo() ? console.log("Have foo") : console.log("Not have foo");
}

foobar();

结果:

(节点:14843)UnhandledPromiseRejectionWarning:未处理的承诺拒绝(拒绝 id:1):false

(node:14843) [DEP0018] DeprecationWarning:不推荐使用未处理的承诺拒绝。将来,未处理的 Promise 拒绝将使用非零退出代码终止 Node.js 进程。

注意:我知道我可以这样解决这个问题:

foo().then(() => {}).catch(() => {});

然后我们“回到”回调异步样式。

我们如何解决这个问题?

【问题讨论】:

  • db.foo 是什么?是猫鼬吗?
  • @estus 不,它是 MongoJS,见这里github.com/mafintosh/mongojs
  • async/await 需要 try/catch。如果你想用 async/await 风格编写这些代码,你可以试试util.promisify,它处理遵循错误优先回调风格的函数。
  • 你觉得foo().catch(console.error)有什么问题?

标签: javascript node.js


【解决方案1】:

将您的代码包装在try-catch 块中。

async function foobar() {
  try {
    await foo() ? console.log("Have foo") : console.log("Not have foo");
  }
  catch(e) {
    console.log('Catch an error: ', e)
  }
}

【讨论】:

  • 我正在使用异步等待来减少不必要的代码。 Try 和 catch 块真的不是这里的目标 - 我可以只使用上面提到的常规回调。
  • @Raz 错误处理不是“不必要的”。你会认为try..catch 在同步代码中是不必要的吗? async 也是如此。
  • @Raz async/await 是一种语法糖,可让您编写看起来像同步的代码。您如何处理同步代码中的错误? --> try/catch。首先,它根本不是为了减少代码(即使情况经常如此)
  • @Raz,我希望你 @estues 和 @Kristianmitk 解决了你的问题。此外,节点只提供warning,如果您不关心错误处理,那么您也可以忽略警告,但我强烈建议不要这样做。为运行时错误添加适当的处理只是一个好习惯。
  • async await 后面应该跟一个 promise 吗?我可以删除承诺并在 foo 函数中返回 truefalse 吗?我试过了,还是不行。
【解决方案2】:

then(() => {}).catch(() => {}) 不需要,因为catch 不一定应该在then 之后。

UnhandledPromiseRejectionWarning 表示承诺没有与catch 同步链接,这导致未处理的拒绝。

async..await 中,应使用try..catch 捕获错误:

async function foobar() {
  try {
    await foo() ? console.log("Have foo") : console.log("Not have foo");
  } catch (error) {
    console.error(error);
  }
}

另一种方法是在顶层处理错误。如果foobar 是应用程序入口点并且不应该被链接到其他任何地方,那么它是:

foobar().catch(console.error);

foo 的问题在于它没有提供有意义的错误。最好应该是:

if (err || !docs) return reject(err);

此外,大多数流行的基于回调的库都承诺避免使用new Promisemongoistmongojs

【讨论】:

    【解决方案3】:

    这里的每个解决方案都只是消除错误,但您可能应该处理错误

    您如何处理它取决于错误以及您所在的应用程序的哪个部分。以下是一些示例。

    你正在编写一个应用程序

    如果您正在编写节点应用程序并抛出异常,您可能希望使用process.exit(1) 退出应用程序并向用户显示错误:

    async function init() {
      await doSomethingSerious();
    }
    
    init().catch(error => {
      console.error(error);
      process.exit(1)
    });
    

    你正在编写一个模块

    如果代码预期错误,您可以捕获它并将其用作值:

    module.exports = async function doesPageExist(page) {
      try {
        await fetchPage(page);
        return true;
      } catch (error) {
        if (error.message === '404') {
          return false;
        }
    
        // Unrecognized error, throw it again
        throw error;
      }
    }
    

    请注意,当错误不是预期的错误时,此示例会重新引发错误。 这很好。处理网络错误是最终用户的责任:

    const doesPageExist = require('my-wonderful-page-checker');
    
    async function init() {
      if (await doesPageExist('https://example.com/nope')) {
        console.log('All good')
      } else {
        console.log('Page is missing ?')
      }
    }
    
    // Just like before
    init().catch(error => {
      console.error(error);
      process.exit(1)
    });
    

    你是用户

    如果您在通过命令行(如 webpack 或 babel)使用预打包的应用程序时看到此错误,这可能意味着该应用程序有错误但未处理。这取决于应用程序或您的输入不正确。请参阅应用程序手册。

    【讨论】:

      猜你喜欢
      • 2017-06-15
      • 1970-01-01
      • 2018-10-11
      • 1970-01-01
      • 1970-01-01
      • 2019-05-02
      • 2018-02-03
      • 2018-03-05
      • 1970-01-01
      相关资源
      最近更新 更多