为什么多层异步功能不能捕获节点最低级别抛出的错误?

akc42

我正在尝试测试某些邮寄代码的失败模式,该模式在最低级别可能会引发错误。测试和抛出的函数之间的所有层都是异步的,并在它们下面的函数上使用await。在最高级别(也在异步函数中,我有一个try catch块。但是,在错误传播到该级别之前,节点抛出未处理的promise异常。

我的测试代码如下所示

beforeEach(function() {
  //set default values - tests can change them
  this.reasons = '';
  this.reschedules = 0;
  this.params.cid = 35124;

  this.startTest = async () => {
    /*  this.confirmation is an async function under test, 
        this.mailer is a mock mailer with an async "send" method
        which will throw an error in the correct test */
    const doner = this.confirmation(this.mailer);  
    // ..other actions related to mocking database access made by confirmation
    await doner;
    return this.mailer.maildata; //provide info on parameters passed to this.mailer
  };
});
it('Failure to send is reported', async function() {
  this.mailer.sendResolve = false; //tell mock mailer to fail send request
  try {
    await this.startTest();
    expect(true).to.be.false;
  } catch(err) {
    expect(err).to.be.instanceOf(Error);
  }
});

模拟邮件有点像这样

class Mailer {
    constructor(user,params){
...
    }
    ...
    async send(subject, to, cc, bcc) {
      this.maildata.subject = subject;
      if (to !== undefined) this.maildata.to = to;
      if (cc !== undefined) this.maildata.cc = cc;
      if (bcc !== undefined) this.maildata.bcc = bcc;
      if (!this.sendResolve) throw new Error('Test Error');
    }
    ...
 }

以及测试代码的摘要

 module.exports = async function(mailer) {
    //get confirm data from database
    const cData = await confirm(mailer.params.cid, mailer.db);
    if (cData.count > 0) {
       // ... format the email message and build it into maildata
       await mailer.send(
        subject,
        emailAddress,
        null,
        process.env.PAS_MAIL_FROM,
        {
          pid:cData.pid,
          type: 'confirmation',
          extra: `Calendar ID ${mailer.params.cid} with procedure ${cData.procedure}`
        }
      );
      debug('message sent, update the database');
      await mailer.db.exec(async connection => {
 ...
       });
      debug('success');
    } else {
      debug('invalid calendarid');
      throw new Error('Invalid Calendar ID');
    }
  };

可以看出,从async send函数返回栈的调用路径try {}catch(){}都是异步函数。但是,当我运行此测试节点时,会输出未处理的承诺拒绝。

我曾尝试使用Visual Studio代码调试器来完成此步骤,但是我迷上了将异步功能包装成承诺提供者的机制。据我所知,正确处理了一层错误,然后在下一层错误了。

这是否意味着每个异步函数都必须具有try catch块才能捕获并抛出任何错误?我找不到任何说明必须这样做的解释。

布赖恩·亚当斯

要回答您的问题:

这是否意味着每个异步函数都必须具有try catch块才能捕获并抛出任何错误?

错误会await像您期望的那样通过-ed调用传播

const assert = require('assert');

const outer = async () => {
  await middle();
}

const middle = async () => {
  await inner();
}

const inner = async () => {
  throw new Error('something bad happened');
}

it('should catch the error', async () => {
  let errorMessage;
  try {
    await outer();
  }
  catch (err) {
    errorMessage = err.message;
  }
  assert(errorMessage === 'something bad happened');  // Success!
});

...所以,您不需要try / catch在每个级别都设置障碍。


追踪未处理的Promise拒绝

await在您的示例代码中,我看不到链可能在何处断裂,但是为了帮助查找未处理的Promise拒绝,您可以unhandledRejection事件添加一个流程处理程序,并查看日志记录,Promise以查看拒绝从何处开始并向后追溯从那里调用堆栈:

const assert = require('assert');

const outer = async () => {
  await middle();
}

const middle = async () => {
  inner();  // <= this will cause an Unhandled Rejection
}

const inner = async () => {
  throw new Error('something bad happened');
}

it('should catch the error', async () => {
  let errorMessage;
  try {
    await outer();
  }
  catch (err) {
    errorMessage = err.message;
  }
  assert(errorMessage === undefined);  // Success!  (broken await chain)
})

process.on('unhandledRejection', (reason, p) => {
  console.log('Unhandled Rejection at:', p);
  console.log('reason:', reason);
});

...在这种情况下记录:

Unhandled Rejection at: Promise {
  <rejected> Error: something bad happened
      at inner (.../code.test.js:12:9)
      at inner (.../code.test.js:8:3)
      at middle (.../code.test.js:4:9)  // <= this is the broken link
      at Context.outer (.../code.test.js:18:11)
      at callFn (...\node_modules\mocha\lib\runnable.js:387:21)
      ...

...指向我们的Error抛出inner,并通过跟踪环比上涨,我们发现middle是无效链接。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

为什么同步睡眠功能不能通过内部承诺使异步?

来自分类Dev

为什么我的删除功能不能将节点从BST中删除?

来自分类Dev

为什么RHR功能不能超载?

来自分类Dev

为什么该记忆功能不能线性运行?

来自分类Dev

为什么列表删除功能不能删除空格?

来自分类Dev

为什么这个功能不能正常工作?

来自分类Dev

为什么我的 Javascript 功能不能正常工作?

来自分类Dev

为什么此Perl随机播放功能不能随机播放?

来自分类Dev

为什么某些Emacs功能不能通过`Mx`使用?

来自分类Dev

为什么此功能不能正确打开和关闭LED?

来自分类Dev

为什么这个jQuery remove功能不能正常工作?

来自分类Dev

为什么我的“获取”功能不能真正获取字符串?

来自分类Dev

为什么Knockout的点击编辑功能不能在表格中使用多个值?

来自分类Dev

为什么仅声明朋友功能不能具有默认参数?

来自分类Dev

为什么循环功能不能与空列表一起使用?

来自分类Dev

为什么我的堆排序功能不能按预期工作?

来自分类Dev

为什么我的功能不能正常工作两次?

来自分类Dev

为什么此功能不能打印所有值?

来自分类Dev

为什么仅声明朋友功能不能具有默认参数?

来自分类Dev

为什么循环功能不能与空列表一起使用?

来自分类Dev

为什么此功能不能正确打开和关闭LED?

来自分类Dev

为什么该功能不能在油脂猴子上使用

来自分类Dev

为什么Linux中的“系统”功能不能运行此shellscript?

来自分类Dev

为什么计数功能不能在Spark中使用mapvalues?

来自分类Dev

为什么信号功能不能使用信号工作?

来自分类Dev

为什么此功能不能在即7,8(延迟和淡入)上起作用?

来自分类Dev

为什么我的类朋友功能不能使用名称空间访问受保护的成员?

来自分类Dev

为什么Laravel中间件中的智能不能识别用户模型中的功能?

来自分类Dev

为什么此功能不能在Selenium正常工作的情况下刮擦表?

Related 相关文章

  1. 1

    为什么同步睡眠功能不能通过内部承诺使异步?

  2. 2

    为什么我的删除功能不能将节点从BST中删除?

  3. 3

    为什么RHR功能不能超载?

  4. 4

    为什么该记忆功能不能线性运行?

  5. 5

    为什么列表删除功能不能删除空格?

  6. 6

    为什么这个功能不能正常工作?

  7. 7

    为什么我的 Javascript 功能不能正常工作?

  8. 8

    为什么此Perl随机播放功能不能随机播放?

  9. 9

    为什么某些Emacs功能不能通过`Mx`使用?

  10. 10

    为什么此功能不能正确打开和关闭LED?

  11. 11

    为什么这个jQuery remove功能不能正常工作?

  12. 12

    为什么我的“获取”功能不能真正获取字符串?

  13. 13

    为什么Knockout的点击编辑功能不能在表格中使用多个值?

  14. 14

    为什么仅声明朋友功能不能具有默认参数?

  15. 15

    为什么循环功能不能与空列表一起使用?

  16. 16

    为什么我的堆排序功能不能按预期工作?

  17. 17

    为什么我的功能不能正常工作两次?

  18. 18

    为什么此功能不能打印所有值?

  19. 19

    为什么仅声明朋友功能不能具有默认参数?

  20. 20

    为什么循环功能不能与空列表一起使用?

  21. 21

    为什么此功能不能正确打开和关闭LED?

  22. 22

    为什么该功能不能在油脂猴子上使用

  23. 23

    为什么Linux中的“系统”功能不能运行此shellscript?

  24. 24

    为什么计数功能不能在Spark中使用mapvalues?

  25. 25

    为什么信号功能不能使用信号工作?

  26. 26

    为什么此功能不能在即7,8(延迟和淡入)上起作用?

  27. 27

    为什么我的类朋友功能不能使用名称空间访问受保护的成员?

  28. 28

    为什么Laravel中间件中的智能不能识别用户模型中的功能?

  29. 29

    为什么此功能不能在Selenium正常工作的情况下刮擦表?

热门标签

归档