简体   繁体   English

在(嵌套)try/catch/finally 块中处理 nodejs 中的错误

[英]Handling errors in nodejs in (nested) try/catch/finally blocks

I'm refactoring my nodejs code.我正在重构我的 nodejs 代码。 I'm implementing transactions using node-postgres.我正在使用 node-postgres 实现事务。 My code now looks like this:我的代码现在看起来像这样:

const controller = async (req, res, next) => {
    const client = await pool.connect()

    try {

        // get the user ID out of the params in the URL
        const { user_id } = req.params

        let query, values, result

        try {
            await client.query('BEGIN')
        } catch (err) {
            throw new CustomError(err)
        }

        try {
            query = 'QUERY_1'
            values = ['VALUES_1']
            result  = await client.query(query, values)
        } catch (err) {
            throw new CustomError(err)
        }

        // handle some stuff

        try {
            query = 'QUERY_2'
            values = ['VALUES_2']
            result  = await client.query(query, values)
        } catch (err) {
            throw new CustomError(err)
        }

        // handle some more stuff

        try {
            await client.query('COMMIT')
        } catch (err) {
            throw new CustomError(err)
        }

        return res.status(200).json({ response: 'ok' })
    } catch (err) {
        await client.query('ROLLBACK')

        return next(new CustomHandleError(400, 'something_went_wrong'))
    } finally {
        client.release()
    }
}

This code works, but I have some questions.这段代码有效,但我有一些问题。 I'm a beginner at nodejs.我是 nodejs 的初学者。

1) In my 'finally' block, I release the client back to the pool. 1)在我的'finally'块中,我将客户端释放回池中。 But when everything is OK, I return the response in the 'try' block.但是当一切正常时,我会在“尝试”块中返回响应。 Online I read that the 'finally' block is ALWAYS executed, so is it OK to return a (good) response in the try block and releasing the client in the finally block?在线我读到'finally'块总是被执行,那么在try块中返回一个(好的)响应并在finally块中释放客户端是否可以?

2) Is it OK (or is it anti-pattern) to nest multiple try catch blocks. 2)嵌套多个try catch块是否可以(或者是反模式)。 The reason is that the node-postgres throws errors but I want to return all errors to a custom error handler, so I catch those errors first and then throw them again in my CustomError handler.原因是 node-postgres 抛出错误,但我想将所有错误返回给自定义错误处理程序,所以我首先捕获这些错误,然后在我的 CustomError 处理程序中再次抛出它们。

Thanks in advance!提前致谢!

You can significant simplify your try/catch handling since all the inner catch blocks all do the same thing and are not necessary:您可以显着简化您的 try/catch 处理,因为所有内部catch块都做同样的事情并且不是必需的:

const controller = async (req, res, next) => {
    const client = await pool.connect()

    try {

        // get the user ID out of the params in the URL
        const { user_id } = req.params

        let query, values, result;
        await client.query('BEGIN');
        query = 'QUERY_1'
        values = ['VALUES_1']
        result  = await client.query(query, values)

        // handle some stuff

        query = 'QUERY_2'
        values = ['VALUES_2']
        result  = await client.query(query, values)

        // handle some more stuff

        await client.query('COMMIT')
        return res.status(200).json({ response: 'ok' })
    } catch (err) {
        await client.query('ROLLBACK')
        return next(new CustomHandleError(400, 'something_went_wrong'))
    } finally {
        client.release()
    }
}

Then, to your questions:然后,针对您的问题:

1) In my 'finally' block, I release the client back to the pool. 1)在我的'finally'块中,我将客户端释放回池中。 But when everything is OK, I return the response in the 'try' block.但是当一切正常时,我会在“尝试”块中返回响应。 Online I read that the 'finally' block is ALWAYS executed, so is it OK to return a (good) response in the try block and releasing the client in the finally block?在线我读到'finally'块总是被执行,那么在try块中返回一个(好的)响应并在finally块中释放客户端是否可以?

Yes, this is a good use of finally .是的,这是finally的一个很好的用途。

2) Is it OK (or is it anti-pattern) to nest multiple try catch blocks. 2)嵌套多个try catch块是否可以(或者是反模式)。 The reason is that the node-postgres throws errors but I want to return all errors to a custom error handler, so I catch those errors first and then throw them again in my CustomError handler.原因是 node-postgres 抛出错误,但我想将所有错误返回给自定义错误处理程序,所以我首先捕获这些错误,然后在我的 CustomError 处理程序中再次抛出它们。

It's OK (not an anti-pattern when it achieves a specific goal), but in this case it is not necessary because all your inner catch() blocks all do the same thing and are all just caught by your outer catch block so you can just keep the outer catch and get rid of all the inner ones.没关系(当它达到特定目标时不是反模式),但在这种情况下没有必要,因为你所有的内部catch()块都做同样的事情并且都被你的外部 catch 块捕获,所以你可以只保留外部捕获并摆脱所有内部捕获。 All your await statements will just go directly to your outer catch if they reject in my code above which all you were doing anyway with all your inner catch statements so they were redundant.如果它们在我上面的代码中拒绝,那么您所有的await语句将只是 go 直接到您的外部catch ,而您在所有内部捕获语句中所做的一切都是多余的。

Some reasons for needing the inner catch are:需要内部捕获的一些原因是:

  1. You want to create a custom error (that is different for each async operation) that you will actually use in the final result of the function.您想要创建一个自定义错误(对于每个异步操作都不同),您将在 function 的最终结果中实际使用该错误。

  2. You want to "handle" an error locally and continue processing down a different code path that is not just an immediate error return.您想在本地“处理”错误并继续处理不同的代码路径,而不仅仅是立即返回错误。 For example, you attempt to load a config file, catch the error and just proceed with the rest of the code in your function with defaults if the config file is not present.例如,您尝试加载配置文件,捕获错误,然后继续执行 function 中代码的 rest,如果配置文件不存在,则使用默认值。

1) Yes, this is good practice. 1)是的,这是一个很好的做法。

2) I don't think it's automatically an anti-pattern, but I'd avoid it if I can find a cleaner way to do it. 2)我认为它不会自动成为反模式,但如果我能找到一种更清洁的方法,我会避免它。

Rule of thumb from Robert C. Robert C 的经验法则。 Martin's suggestion from his book 'Clean Code': Martin 在他的《清洁代码》一书中的建议:

if the keyword 'try' exists in a function, it should be the very first word in the function and that there should be nothing after the catch/finally blocks.如果关键字“try”存在于 function 中,它应该是 function 中的第一个单词,并且在 catch/finally 块之后应该没有任何内容。

If you have a chance, then avoid nesting try-catches.如果有机会,请避免嵌套尝试捕获。 Blocks out into separate functions分块成单独的功能

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM