【问题标题】:Can I catch an error from async without using await?我可以在不使用 await 的情况下从异步中捕获错误吗?
【发布时间】:2015-08-19 10:16:17
【问题描述】:

是否可以捕获来自非等待异步调用的错误,将其发送到原始封装 try/catch,或引发未捕获的异常?

这是我的意思的一个例子:

async function fn1() {
    console.log('executing fn1');
}

async function fn2() {
    console.log('executing fn2');
    throw new Error('from fn2');
}

async function test() {
    try {
        await fn1();
        fn2();
    }
    catch(e) {
        console.log('caught error inside test:', e);
    }
}

test();

在这种情况下,fn2抛出的错误会被默默吞噬,绝对不会被原来的try/catch捕捉到。我相信这是预期的行为,因为 fn2 很可能会被推到事件循环中以在将来的某个时间完成,而 test 并不关心它何时完成(这是有意的)。

除了将try/catch 放在fn2 内部并执行诸如发出错误之类的操作之外,有什么方法可以确保错误不会被这样的结构意外吞没?我什至会在不知道如何捕获它的情况下解决一个未捕获的错误,我认为——我不希望抛出的错误是我正在编写的典型程序流程,但是吞下错误会使调试相对烦人。

旁注,我正在使用 Babel 使用 babel-runtime 转换转换代码,并使用节点执行它。

【问题讨论】:

  • 我不确定你想达到什么目的,但有理由不使用承诺吗?
  • 使用支持未处理拒绝检测的承诺库。
  • 汤姆,不是真的,不。我故意在 promises 上使用 async/await 来看看此时可以用 es7 语法做什么,这是我在玩它时遇到的一个问题。 Bergi,如果目前没有其他选择(我怀疑可能是这种情况),我肯定会回到那个位置。
  • @dvlsg 请注意,使用 Babel,您有一个 bluebirdCoroutines 转换,可让您将 bluebird Promise 与本机 async/await 一起使用。

标签: javascript async-await promise ecmascript-2016


【解决方案1】:

处理未处理的被拒绝的原生 Promise(并且 async/await 使用原生 Promise)是 V8 现在支持的一项功能。它在最新的 Chrome 中用于在未处理拒绝的 Promise 时输出调试信息;在the Babel REPL 尝试以下操作:

async function executor() {
  console.log("execute");
}

async function doStuff() {
  console.log("do stuff");
  throw new Error("omg");
}

function handleException() {
  console.error("Exception handled");
}

(async function() {
  try {
      await executor();
      doStuff();
  } catch(e) {
      handleException();
  }
})()

您会看到,即使来自doStuff() 的异常丢失(因为我们调用它时没有使用await),Chrome 也会记录一个被拒绝的承诺未处理到控制台:

这在 Node.js 4.0+ 中也可用,但需要收听 a special unhandledRejection event

process.on('unhandledRejection', function(reason, p) {
    console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason);
    // application specific logging, throwing an error, or other logic here
});

【讨论】:

  • 啊,完美。感谢 github 问题的链接,我会密切关注这些问题,在测试我正在做的事情时,我会暂时改用 io.js。
  • 啊,最后一个警告——我必须添加 process.on('unhandledRejection', err => { throw err; }); 才能让它在 io.js 中按预期工作,基于他们的 unit tests。仍然有点 hacky,但我收到了一个错误,其中包含(某种)有用的堆栈跟踪,这种方式。
  • 玩这个,似乎无法捕获从没有await 调用的async 函数引发的错误。这是正确的看待它的方式吗?
  • @dvlsg 做process.on('unhandledRejection', err => { throw err; }); 绝对没问题。另请注意,由于 NodeJS 和 io.js 正在合并,因此可以安全地使用此功能,因为它将在 Node 中收敛。
  • 作为跟进,现在 Node 4.0 已经发布,我可以确认 process.on('unhandledRejection', err => { /* ... stuff */ }); 在 iojs 合并后按预期工作,并且仍然有必要防止意外吞下未捕获的拒绝(而不是Chrome 中的行为)。
【解决方案2】:

如果您熟悉promises,请使用它们。如果没有,你可以试试这个例子,让你的代码更加异步:)

function fn1(callback) {
    console.log('executing fn1');
    callback({status: true});
}

function fn2(callback) {
    console.log('executing fn2');
    callback({status: false});
}

function test() {
    fn1(function(result) {
        console.log('fn1 executed with status ' + result.status);
    });

    fn2(function(result) {
        console.log('fn2 executed with status ' + result.status);
        if (result.status == false) {
            console.log('error in fn2');
        }
    });
}

test();

【讨论】:

  • 感谢您的回复。不过,在这种情况下,我有意使用 ES7 async/await。我知道,我很固执,而且我使用的功能甚至还没有被完全接受,但它们显着提高了我的实际代码的语法和可读性(它涉及async 函数中的长/无限 while 循环await 在循环内)。
猜你喜欢
  • 2019-10-27
  • 1970-01-01
  • 2016-10-12
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多