我应该避免在 Node js 上的每个 async/await 中使用 try catch 吗?

2023-11-26

这是我在单元测试时遇到的一个设计问题。 让我们深入研究这个例子:

想象一下:

async function foo() {
    try {
        return apiCall()
    }
    catch (e) {
        throw new CustomError(e);
    } 
}



async function bar() {
    return foo()
}



async function main() {
    try {
        await bar()
    }catch(e) {
        console.error(e)
    }
}

main()

我们在这里看到什么?唯一没有 try-catch 块的函数是 bar。 但如果 foo 失败,它应该被 main catch 捕获。

虽然像这样进行单元测试

describe('testing bar', () => {
    it('foo should throw', () => {
        foo.mockImplementantion(() => { throw new CustomError('error')});
        bar()
        .then((result) => console.log(result))
        .catch((err) => { exepect(err).toBeInstanceOf(CustomError)}) // this is what we are testing
    })
})

我们看到的输出是未处理的承诺拒绝已登录到控制台。

所以,我的问题是...即使我知道main()会捕获错误,我应该在所有异步函数中使用 try-catch 块吗?


try..catch如果函数能够从错误中恢复、执行日志记录等副作用或重新抛出更有意义的错误,则可能有必要。

If CustomError比错误更可取apiCall然后可以扔try..catch必须的,否则就没有。还有问题foo是它只处理同步错误。为了处理被拒绝的承诺,应该是return await apiCall(),这是一个已知的陷阱async.

未捕获的拒绝是不必要的,它们目前会导致UnhandledPromiseRejectionWarning预计在未来的版本中 Node 会崩溃。最好在顶层以有意义的方式处理错误,因此main需要捕获错误。这可以委托给process uncaughtRejection事件处理程序,但保持不应达到的额外错误处理级别可能是有益的。

我们看到的输出是控制台中记录了未处理的承诺拒绝。

这不应该发生。拒绝需要通过测试来处理。上面解释了一种可能的故障点,foo可以返回原始错误apiCall代替CustomError如果它没有被正确地嘲笑,这将达不到预期并导致未处理的拒绝catch()。另一个失败点是测试有不受约束的承诺,因为它没有返回,测试总是通过。

使用 Promise 的异步测试应该始终返回 Promise。这可以通过使用来改进async..await. foo is async,它应该总是返回一个承诺:

it('foo should throw', async () => {
    foo.mockImplementantion(() => { return Promise.reject(new CustomError('error')) });
    await expect(bar()).rejects.toThrow(CustomError);
})

现在即使foo模拟失败(foo模拟不会影响bar如果它们在同一模块中定义,如图所示)和bar拒绝一些不符合的东西CustomError,这将被断言。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我应该避免在 Node js 上的每个 async/await 中使用 try catch 吗? 的相关文章

随机推荐