Каков правильный шаблон для всплывающих и перехвата исключений с помощью async/await?
Я изо всех сил пытаюсь сосредоточиться на том, что является правильным шаблоном для обработки ошибок во вложенных подпрограммах await / async, сохраняя при этом код чистым и простым. (несмотря на чтение бесчисленных статей и блогов)
У меня есть набор функций, которые (принципиально) похожи на следующее:
async validate(params) {
const recCount = await this._getCount(db, params);
if( recCount > 0 )
return "Record already exists";
}
_getCount - это оболочка, которая создает sql
async _getCount(conn, regdata) {
const sql = "SELECT count(*) AS 'count' FROM myTable WHERE product = ? and category = ?";
let rows = await this._execSQL(conn, sql, [ regdata.product, regdata.category ]);
return rows[0].count;
}
и фактический запрос выполняется следующим образом:
async _execSQL(conn, sql, data) {
const [ rows ] = await conn.query(sql, data);
return rows;
}
Метод conn.query (из библиотеки mysql2/ обещания) отклонит обещание, если запрос не выполнен.
Итак, мой вопрос становится, каков правильный шаблон для обработки исключений?
В синхронном мире я ничего не мог сделать ни с _execSQL, ни с _getCount, а просто поймал исключение в validate; просто естественно позволить исключению всплыть.
Тем не менее, в асинхронном мире, как я могу сделать эквивалент, не получая исключение "Необработанное обещание"?
Я застрял с необходимостью отлавливать ошибки в каждой асинхронной процедуре на всех уровнях?
Или есть лучший способ, не используя что-то вроде process.on('unhandledRejection',...)
что такое ощущение, что я обхожу проблему?
РЕДАКТИРОВАТЬ: добавлен пример и трассировка стека
Итак, я фактически добавил этот код в свое приложение и поместил try / catch в validate
функция. Дословный код:
async validate(db, params) {
let recCount;
try {
recCount = await this._getCount(db, params);
} catch (err) {
console.log('Caught error', err);
}
if (recCount > 0) return 'Record already exists';
}
async _getCount(conn, regdata) {
const sql = "SELECT count(*) AS 'count' FROM myTable WHERE product = ? and category = ?";
let rows = await this._execSQL(conn, sql, [ regdata.product, regdata.category ]);
return rows[0].count;
}
async _execSQL(conn, sql, data) {
const [ rows ] = await conn.query(sql, data);
return rows;
}
У меня есть обработчик события unhandledRejection, который сообщает о событии вместе с внутренним исключением и трассировкой стека. Вот что он выбрасывает:
Stack Trace:
AppError: Unhandled promise rejection. Plugin may not be properly handling error.
at process.on (D:\Development\website\service\server.js:73:5)
at emitTwo (events.js:126:13)
at process.emit (events.js:214:7)
at emitPendingUnhandledRejections (internal/process/promises.js:108:22)
at process._tickCallback (internal/process/next_tick.js:189:7)
Inner Error:
{ "message": "connect ECONNREFUSED 127.0.0.1:3306", "code": "ECONNREFUSED", "errno": "ECONNREFUSED" }
Error: connect ECONNREFUSED 127.0.0.1:3306
at PromisePool.query (D:\Development\website\webhooks\node_modules\mysql2\promise.js:323:22)
at Registration._execSQL (D:\Development\website\webhooks\plugins\registration.js:108:31)
at Registration._logRequest (D:\Development\website\webhooks\plugins\registration.js:179:14)
at Registration.register (D:\Development\website\webhooks\plugins\registration.js:52:8)
at Router.exec (D:\Development\website\service\router.js:119:20)
at IncomingMessage.request.on (D:\Development\website\service\server.js:292:47)
at emitNone (events.js:106:13)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
1 ответ
Вы всегда можете позволить пузырям отказов и выбрать лучший уровень, чтобы поймать их:
async function f1() { return await f2(); }
async function f2() { return await f3(); }
async function f3() {
return Promise.reject('no way!');
// or
throw 'no way!';
}
async function f_await() {
try {
console.log('never succeeds here', await f1());
} catch (err) {
console.log('I check for errors at the level I prefer!');
throw 'I can even intercept and rethrow!';
}
return 'or i can keep going like eveything is fine';
}
function f_then() {
f1().then(console.log.bind(null, 'never succeeds here'))
.catch(function (err) {
console.log('I check for errors at the level I prefer!');
throw 'I can even intercept and rethrow!';
}).then(function () {
return 'or i can keep going like eveything is fine';
});
}
Если вы запускаете необработанное предупреждение об отказе, это потому, что... вы не обрабатывали какое-то отклонение в какой-либо точке цепочки, в то время как вам всегда нужно: даже в синхронном коде, если исключение возникает и никогда не перехватывается, компьютер будет скажу вам, как это плохо.
Если вы думаете, что лучший способ справиться с отклоненным запросом SQL в вашем коде - это validate
, а затем пойти на это: окружить это await
с try
/catch
заблокировать и "обработать" ошибку в catch
как вы думаете, лучше... Не уверен, что я вижу проблему здесь!