Búsqueda de sitios web

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.

Artículos relacionados