javascript - Colocación correcta del bloque try/catch al usar async/await no inmediato
He estado usando async/await durante 6 meses y me ha encantado el azúcar sintáctico. Normalmente lo uso de la manera tradicional:
try {
await doSomethingAsync()
}
catch (e) {}
Recientemente he empezado a experimentar con no esperar inmediatamente para poder ejecutar algo de código adicional en este contexto antes de esperar los datos asíncronos, como:
let p = doSometiongAsync()
... do more stuff
await p;
o :
let p1 = doJob1();
let p2 = doJob2();
... do more synchronous stuff ...
await p1;
await p2;
La pregunta es, ¿dónde está la colocación correcta de los bloques try/catch para asegurarse de que los errores (ya sean sincrónicos o asincrónicos) dentro de las llamadas se capturen correctamente? ¿Es alrededor de la llamada a la función inicial:
try {
let p = doSomethingAsync()
} catch(errors) {}
... do stuff ...
await p
¿O intentar un bloque try alrededor del await... o dos bloques try diferentes, uno para cada uno?
try {
let p = doSomethingAsync()
} catch(errors) {}
... do stuff
try {
await p;
} catch (evenmoreerrors) {}
¡gracias!
Respuesta #1
Depende de lo que sea doSomethingAsync: una función async, o una función no async que devuelve una promesa.
Si es una función async
...solo necesitas el try/catch alrededor del await; una función async nunca lanza excepciones sincrónicamente (incluso si la excepción es lanzada por la parte inicial sincrónica de la misma).
Ejemplo :
async function foo() {
// Note this is in the synchronous portion
console.log("synchronous part of foo");
if (true) {
throw new Error();
}
return new Promise(resolve => {
resolve();
});
}
(async () => {
const p = foo(); // No uncaught error
try {
await p;
} catch (e) {
console.log("Caught the error");
}
})().catch(e => {
console.log("Failed to catch it!");
});Si es una función no async que devuelve una promesa
...entonces, dependiendo de la función, es posible que necesites try/catch en ambos lugares, o no, dependiendo de cómo esté escrita. Si puede lanzar una excepción en su código sincrónico, necesitas try/catch alrededor de eso. Y necesitas try/catch alrededor del await en caso de rechazo de la promesa.
Ejemplo de no manejar la parte sincrónica:
function foo() {
// Note this is in the synchronous portion
console.log("synchronous part of foo");
if (true) {
throw new Error();
}
return new Promise(resolve => {
resolve();
});
}
(async () => {
const p = foo(); // No uncaught error
try {
await p;
} catch (e) {
console.log("Caught the error");
}
})().catch(e => {
console.log("Failed to catch it!");
});Ejemplo de fallo al capturar el rechazo de la promesa:
function foo() {
// Note this is in the synchronous portion
console.log("synchronous part of foo");
return new Promise((resolve, reject) => {
reject();
});
}
(async () => {
try {
const p = foo();
} catch (e) {
console.log("Caught the error");
}
await p;
})().catch(e => {
console.log("Failed to catch it!");
});Respuesta #2
En ambos casos pueden ocurrir errores, uno en el resultado de la llamada asincrónica, y otro también puede ocurrir, si tienes alguna lógica antes de la declaración return de la llamada asincrónica, cuando tu función no es async. Depende de tu lógica dónde poner try/catch.
Si sabes que un error puede estar solo en la llamada asíncrona, coloca try/catch solo en la declaración await.
