异步等待承诺上的 UnhandledPromiseRejectionWarning

Posted

技术标签:

【中文标题】异步等待承诺上的 UnhandledPromiseRejectionWarning【英文标题】:UnhandledPromiseRejectionWarning on async await promise 【发布时间】: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)有什么问题? 【参考方案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)使用预打包的应用程序时看到此错误,这可能意味着该应用程序有错误但未处理。这取决于应用程序或您的输入不正确。请参阅应用程序手册。

【讨论】:

以上是关于异步等待承诺上的 UnhandledPromiseRejectionWarning的主要内容,如果未能解决你的问题,请参考以下文章

在自定义承诺上使用异步等待

在自定义承诺上使用异步等待

异步等待所有承诺

在异步/等待中包装承诺

Javascript - 异步等待和获取 - 返回值,而不是承诺?

等待/异步如何处理未解决的承诺