Обработка ошибок в nodejs во (вложенных) блоках try / catch / finally - PullRequest
0 голосов
/ 08 мая 2020

Я занимаюсь рефакторингом своего nodejs кода. Я реализую транзакции с использованием node- postgres. Теперь мой код выглядит так:

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()
    }
}

Этот код работает, но у меня есть несколько вопросов. Я новичок в nodejs.

1) В моем блоке «finally» я возвращаю клиента в пул. Но когда все в порядке, я возвращаю ответ в блоке try. В сети я прочитал, что блок 'finally' выполняется ВСЕГДА, так что можно ли вернуть (хороший) ответ в блоке try и освободить клиента в блоке finally?

2) Это нормально (или это анти-шаблон) для вложения нескольких блоков try catch. Причина в том, что node- postgres выдает ошибки, но я хочу вернуть все ошибки пользовательскому обработчику ошибок, поэтому я сначала перехватываю эти ошибки, а затем снова бросаю их в свой обработчик CustomError.

Заранее спасибо !

Ответы [ 2 ]

2 голосов
/ 08 мая 2020

Вы можете значительно упростить обработку 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()
    }
}

Затем на ваши вопросы:

1) В моем блоке «finally» я возвращаю клиента в пул. Но когда все в порядке, я возвращаю ответ в блоке try. В сети я прочитал, что блок finally выполняется ВСЕГДА, так что можно ли вернуть (хороший) ответ в блоке try и освободить клиента в блоке finally?

Да, это нормально. хорошее использование finally.

2) Можно ли (или это анти-шаблон) вкладывать несколько блоков try catch. Причина в том, что узел- postgres выдает ошибки, но я хочу вернуть все ошибки пользовательскому обработчику ошибок, поэтому я сначала отлавливаю эти ошибки, а затем снова бросаю их в свой обработчик CustomError.

Это нормально (не анти-шаблон, когда он достигает определенной цели c), но в этом случае это не обязательно, потому что все ваши внутренние блоки catch() делают одно и то же и все просто захватываются вашим внешним блоком catch так что вы можете просто оставить внешнюю защелку и избавиться от всех внутренних. Все ваши await операторы будут просто go непосредственно на ваш внешний catch, если они отклонят мой код, выше которого вы все равно делали со всеми своими внутренними операторами catch, поэтому они были избыточными.

Некоторые причины для необходимости внутреннего улова:

  1. Вы хотите создать настраиваемую ошибку (которая различается для каждой операции asyn c), которую вы фактически будете использовать в конечном результате функции .

  2. Вы хотите «обработать» ошибку локально и продолжить обработку по другому пути кода, который не является просто немедленным возвратом ошибки. Например, вы пытаетесь загрузить файл конфигурации, перехватить ошибку и просто продолжить выполнение остальной части кода в вашей функции со значениями по умолчанию, если файл конфигурации отсутствует.

1 голос
/ 08 мая 2020

1) Да, это хорошая практика.

2) Я не думаю, что это автоматически анти-шаблон, но я бы избегал этого, если бы смог найти более чистый способ сделать это.

Эмпирическое правило от Роберта C. Предложение Мартина из его книги «Чистый код»:

если ключевое слово «try» существует в функции, оно должно быть самым первым словом в функции и что после catch / не должно быть ничего. finally блоки.

Если у вас есть шанс, то избегайте вложения пробных ловушек. Выделяется на отдельные функции

...