visual try nodejs ejemplo catch node.js async-await ecmascript-2017

node.js - nodejs - Try/catch blocks con async/await



try catch typescript (7)

Alternativa similar al manejo de errores en Golang

Debido a que async / await usa promesas ocultas, puede escribir una pequeña función de utilidad como esta:

export function catchEm(promise) { return promise.then(data => [null, data]) .catch(err => [err]); }

Luego, impórtelo cada vez que necesite detectar algunos errores y ajuste su función asíncrona que le devuelve una promesa.

import catchEm from ''utility''; async performAsyncWork() { const [err, data] = await catchEm(asyncFunction(arg1, arg2)); if (err) { // handle errors } else { // use data } }

Estoy cavando en la función async / wait del nodo 7 y sigo tropezando con código como este

function getQuote() { let quote = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; return quote; } async function main() { try { var quote = await getQuote(); console.log(quote); } catch (error) { console.error(error); } } main();

Esta parece ser la única posibilidad de resolver / rechazar o devolver / lanzar con async / wait, sin embargo, ¿v8 no optimiza el código dentro de los bloques try / catch?

¿Hay alternativas?


Alternativas

Una alternativa a esto:

async function main() { try { var quote = await getQuote(); console.log(quote); } catch (error) { console.error(error); } }

sería algo como esto, usando promesas explícitamente:

function main() { getQuote().then((quote) => { console.log(quote); }).catch((error) => { console.error(error); }); }

o algo así, usando el estilo de paso de continuación:

function main() { getQuote((error, quote) => { if (error) { console.error(error); } else { console.log(quote); } }); }

Ejemplo original

Lo que hace su código original es suspender la ejecución y esperar a que se cumpla la promesa devuelta por getQuote() . Luego continúa la ejecución y escribe el valor devuelto en var quote y luego lo imprime si la promesa se resolvió, o lanza una excepción y ejecuta el bloque catch que imprime el error si la promesa fue rechazada.

Puede hacer lo mismo usando Promise API directamente como en el segundo ejemplo.

Actuación

Ahora, por el rendimiento. ¡Probémoslo!

Acabo de escribir este código: f1() da 1 como valor de retorno, f2() arroja 1 como excepción:

function f1() { return 1; } function f2() { throw 1; }

Ahora llamemos al mismo código millones de veces, primero con f1() :

var sum = 0; for (var i = 0; i < 1e6; i++) { try { sum += f1(); } catch (e) { sum += e; } } console.log(sum);

Y luego cambiemos f1() a f2() :

var sum = 0; for (var i = 0; i < 1e6; i++) { try { sum += f2(); } catch (e) { sum += e; } } console.log(sum);

Este es el resultado que obtuve para f1 :

$ time node throw-test.js 1000000 real 0m0.073s user 0m0.070s sys 0m0.004s

Esto es lo que obtuve para f2 :

$ time node throw-test.js 1000000 real 0m0.632s user 0m0.629s sys 0m0.004s

Parece que puede hacer algo como 2 millones de lanzamientos por segundo en un proceso de subproceso único. Si está haciendo más que eso, entonces es posible que deba preocuparse por eso.

Resumen

No me preocuparía por cosas así en Node. Si cosas así se usan mucho, los equipos V8 o SpiderMonkey o Chakra lo optimizarán eventualmente y todos lo seguirán, no es que no esté optimizado como principio, simplemente no es un problema.

Incluso si no está optimizado, entonces aún argumentaría que si está maximizando su CPU en Node, entonces probablemente debería escribir su número en C: para eso están los complementos nativos, entre otras cosas. O tal vez cosas como node.native serían más adecuadas para el trabajo que Node.js.

Me pregunto cuál sería un caso de uso que necesita lanzar tantas excepciones. Por lo general, lanzar una excepción en lugar de devolver un valor es, bueno, una excepción.


Me gustaría hacer de esta manera :)

const sthError = () => Promise.reject(''sth error''); const test = opts => { return (async () => { // do sth await sthError(); return ''ok''; })().catch(err => { console.error(err); // error will be catched there }); }; test().then(ret => { console.log(ret); });

Es similar al error de manejo con co

const test = opts => { return co(function*() { // do sth yield sthError(); return ''ok''; }).catch(err => { console.error(err); }); };


Una alternativa al bloque try-catch es await-to-js lib. A menudo lo uso. Por ejemplo:

import to from ''await-to-js''; async function main(callback) { const [err,quote] = await to(getQuote()); if(err || !quote) return callback(new Error(''No Quote found''); callback(null,quote); }

Esta sintaxis es mucho más limpia en comparación con try-catch.


Una alternativa más limpia sería la siguiente:

Debido al hecho de que cada función asíncrona es técnicamente una promesa

Puede agregar capturas a las funciones cuando las llame con wait

async function a(){ let error; // log the error on the parent await b().catch((err)=>console.log(''b.failed'')) // change an error variable await c().catch((err)=>{error=true; console.log(err)}) // return whatever you want return error ? d() : null; } a().catch(()=>console.log(''main program failed''))

No es necesario que intente capturar, ya que todos los errores de promesas se manejan y no tiene errores de código, ¡puede omitir eso en el padre!

Digamos que está trabajando con mongodb, si hay un error, es posible que prefiera manejarlo en la función que lo llama que hacer envoltorios o usar try catches.


catch de esta manera, en mi experiencia, es peligroso. Se detectará cualquier error arrojado en toda la pila, no solo un error de esta promesa (que probablemente no sea lo que desea).

El segundo argumento para una promesa ya es una devolución de llamada de rechazo / falla. Es mejor y más seguro usar eso en su lugar.

Aquí hay un mecanografiado typesafe one-liner que escribí para manejar esto:

function wait<R, E>(promise: Promise<R>): [R | null, E | null] { return (promise.then((data: R) => [data, null], (err: E) => [null, err]) as any) as [R, E]; } // Usage const [currUser, currUserError] = await wait<GetCurrentUser_user, GetCurrentUser_errors>( apiClient.getCurrentUser() );


async function main() { var getQuoteError var quote = await getQuote().catch(err => { getQuoteError = err } if (getQuoteError) return console.error(err) console.log(quote) }

Alternativamente, en lugar de declarar una posible var para mantener un error en la parte superior, puede hacer

if (quote instanceof Error) { // ... }

Aunque eso no funcionará si se produce algo como TypeError o Error de referencia. Sin embargo, puede asegurarse de que es un error regular con

async function main() { var quote = await getQuote().catch(err => { console.error(err) return new Error(''Error getting quote'') }) if (quote instanceOf Error) return quote // get out of here or do whatever console.log(quote) }

Mi preferencia por esto es envolver todo en un gran bloque try-catch donde se crean múltiples promesas que pueden hacer que resulte engorroso manejar el error específicamente para la promesa que lo creó. Con la alternativa de ser múltiples bloques try-catch que encuentro igualmente engorrosos