Могу ли я поймать ошибку из async без ожидания?
Могут ли быть обнаружены ошибки от не ожидаемого асинхронного вызова, отправлены в исходный инкапсулирующий try/catch или поднять неперехваченное исключение?
Вот пример того, что я имею в виду:
async function fn1() {
console.log('executing fn1');
}
async function fn2() {
console.log('executing fn2');
throw new Error('from fn2');
}
async function test() {
try {
await fn1();
fn2();
}
catch(e) {
console.log('caught error inside test:', e);
}
}
test();
В этом случае ошибка, выброшенная из fn2
, будет проглатываться молча, и определенно не будет обнаружена исходная try/catch
. Я считаю, что это ожидаемое поведение, так как fn2
, скорее всего, сбрасывается в цикл событий, чтобы закончить в какой-то момент в будущем, а test
не заботится о том, когда он заканчивается (что является намеренным).
Есть ли способ гарантировать, что ошибки не были случайно проглочены такой структурой, если не положить внутри try/catch
try/catch
и сделать что-то вроде испускания ошибки? Я бы даже согласился на непродуманную ошибку, не зная, как ее поймать, я думаю - я не ожидаю, что брошенные ошибки станут типичным потоком программы с тем, что я пишу, но проглатывание ошибок делает его относительно раздражающим для отладки.
Боковое замечание, я использую Babel для перевода кода с использованием преобразования babel-runtime и выполнения его с помощью node.
Ответы
Ответ 1
Работа с необработанными отклоненными нативными обещаниями (а async/await использует нативные обещания) - теперь эта функция поддерживается в V8. Он использовался в последней версии Chrome для вывода отладочной информации, когда отклоненное обещание не обрабатывается; попробуйте следующее на Вавилонском репл:
async function executor() {
console.log("execute");
}
async function doStuff() {
console.log("do stuff");
throw new Error("omg");
}
function handleException() {
console.error("Exception handled");
}
(async function() {
try {
await executor();
doStuff();
} catch(e) {
handleException();
}
})()
Вы видите, что даже если исключение из doStuff()
потеряно (поскольку мы не используем await
при его вызове), Chrome регистрирует, что отклоненное обещание не было обработано на консоли:
Это также доступно в Node.js 4. 0+, хотя требуется прослушивание специального события unhandledRejection
:
process.on('unhandledRejection', function(reason, p) {
console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason);
// application specific logging, throwing an error, or other logic here
});
Ответ 2
Если вы знакомы с promises, используйте их. Если нет, вы можете попробовать этот пример, чтобы сделать код более асинхронным:)
function fn1(callback) {
console.log('executing fn1');
callback({status: true});
}
function fn2(callback) {
console.log('executing fn2');
callback({status: false});
}
function test() {
fn1(function(result) {
console.log('fn1 executed with status ' + result.status);
});
fn2(function(result) {
console.log('fn2 executed with status ' + result.status);
if (result.status == false) {
console.log('error in fn2');
}
});
}
test();