try-catch en javascript ... ¿no es una buena práctica?

69

Hay una disposición para el bloque try-catch en javascript . Si bien en Java o en cualquier otro idioma es obligatorio tener un manejo de errores, no veo a nadie que los use en JavaScript en mayor medida. ¿No es una buena práctica o simplemente no los necesitamos en JavaScript?

akp
fuente
2
While in java or *any other language* it is mandatory to have error handling...- Realmente no. Java, sí, pero hay muchos lenguajes que no insisten en try-catch (como C #).
Jim G.
Es porque no puede usarlos en un entorno asíncrono. Los uso a menudo mediante código de sincronización por un nivel de abstracción más bajo, por ejemplo, transformando algo en algo, etc ...
inf3rno
Apuesto a que ves más try-catch's en el código del lado del servidor que el código del lado del cliente. La mayor parte del código del lado del cliente que conoce no está haciendo nada importante. Apuesto a que minimizar KB en el futuro es más importante que recuperarse de cada error, en la mayoría de las aplicaciones y circunstancias del lado del navegador.
svidgen
Hay otra forma de evitar intentar atrapar usando maybe y O (mónadas) teníamos un scrapper web escrito en el nodo. Pudimos eliminar todos los intentos de captura usándolo.
user93

Respuestas:

66

Se deben evitar throwerrores como la forma de pasar las condiciones de error en las aplicaciones.

La throwdeclaración solo debe usarse "Para que esto nunca ocurra, choque y arda. No se recupere elegantemente de ninguna manera"

try catch sin embargo, se usa en situaciones en las que los objetos host o ECMAScript pueden arrojar errores.

Ejemplo:

var json
try {
    json = JSON.parse(input)
} catch (e) {
    // invalid json input, set to null
    json = null
}

Las recomendaciones en la comunidad node.js es que pase errores en devoluciones de llamada (porque los errores solo ocurren para operaciones asincrónicas) como primer argumento

fs.readFile(uri, function (err, fileData) {
    if (err) {
        // handle
        // A. give the error to someone else
        return callback(err)
        // B. recover logic
        return recoverElegantly(err)
        // C. Crash and burn
        throw err
    }
    // success case, handle nicely
})

También hay otros problemas, como try / catch, que es realmente costoso y feo, y simplemente no funciona con operaciones asincrónicas.

Entonces, dado que las operaciones síncronas no deberían arrojar un error y no funciona con operaciones asíncronas, nadie usa try catch excepto los errores lanzados por objetos host o ECMAScript

Raynos
fuente
2
No iría tan lejos como para decir que nadie usa try catch, es la herramienta incorrecta para el trabajo en la mayoría de los casos. Cuando existen circunstancias verdaderamente excepcionales, puede valer la pena lanzar un Error, pero son pocos y distantes entre sí.
zzzzBov
77
@zzzzBov No hay nada de malo en arrojar errores para el caso C, bloquearse y quemarse. Simplemente no creo que deba atrapar errores y recuperarse. Por ejemplo, document.getElementByIdno se lanza cuando el elemento no existe, solo regresa null. Lo mismo se puede hacer para casi todos los casos
Raynos el
44
@Raynos, lanzar desde una función de sincronización es totalmente aceptable y tiene sentido en ese caso de uso. Devolver el error a la devolución de llamada es asincrónico como el error de lanzamiento es sincronizar.
sbartell
¿@Raynos tiene algún buen consejo para evitar el uso de Errores / Excepciones para el control de flujo en el lado del cliente (entorno no Node)? He encontrado esta publicación en StackOverflow , pero está orientada principalmente a Java
blong
@ b.long simple. No arrojes errores nunca. Problema resuelto.
Raynos
32

Try / catch en Javascript no es tan a prueba de balas como en otros idiomas, debido a la naturaleza asincrónica de Javascript. Considera este fragmento:

try {
    setTimeout(function() {
        do_something_that_throws();
    }, 1000);
}
catch (e) {
    alert("You won't see this!");
}

El problema es que el flujo de control abandona el trybloque antes de do_something_that_throws()ejecutarse, por lo que el error arrojado dentro de la devolución de llamada nunca se detecta.

Por lo tanto, try / catch es básicamente inapropiado en muchos casos, y no siempre es obvio si algo ejecuta el código de forma asincrónica o no. Afortunadamente, javascript con su peculiar modismo de devolución de llamada asincrónica de un solo subproceso y su soporte para cierres reales proporciona una alternativa elegante: manejo de errores de estilo de paso de continuación. Simplemente pase la respuesta adecuada a cualquier error como una función, por ejemplo:

setTimeout(function () {
    do_something_that_calls_err(function(err) {
        alert("Something went wrong, namely this: " + err);
    }),
    1000);
tdammers
fuente
55
tampoco es a prueba de balas en otros idiomas. Transfiera ese código a cualquier idioma que admita devoluciones de llamada asincrónicas y también fallará.
Raynos
2
@Raynos: Tienes razón; sin embargo, otros idiomas (o más bien, sus culturas de apoyo) no compran esto en gran medida en el lenguaje de devolución de llamada asincrónica como lo hace Javascript, y debido a la naturaleza de subprocesos múltiples de la mayoría de los otros entornos, las deficiencias de try / catch son más obvias y rodeado de muchas otras advertencias, por lo que las personas naturalmente caminan con cuidado en situaciones de devolución de llamada multiproceso / asincrónicas, y son más conscientes de las posibles dificultades.
tdammers
¿Esto se debe realmente a la "naturaleza asincrónica" de JavaScript? Hasta donde puedo ver, Try / Catch podría teóricamente funcionar de manera léxica, como los identificadores están cerrados léxicamente; Simplemente no funciona así en JavaScript.
Brian Gordon
2
En node.js> = 0.8 vale la pena señalar que es posible intentar / atrapar de forma asincrónica, consulte mi pregunta stackoverflow.com/questions/14301839/…
Benjamin Gruenbaum
¿La única alternativa a try-catch síncrono es el estilo de paso de continuación asíncrono?
CMCDragonkai
23

Muchas de estas respuestas son un poco antiguas y no tienen en cuenta las nuevas funciones de ES7 asyncy await.

Usando async/ awaitahora puede obtener un flujo de control asincrónico como desee:

async function email(address) {
  try {
    // Do something asynchronous that may throw...
    await sendEmail({ to: address, from: '[email protected]`, subject: 'Hello' })
  } catch(err) {
    if (err instanceof SomeCustomError) {
      elegantlyHandleError(err)
    } else {
      throw err
    } 
  }
})

Obtenga más información sobre async/ awaitaquí . Puedes usar async/ awaitahora usando babel .

Dana Woodman
fuente
Pero es similar a un código sincrónico
Atul Agrawal
@AtulAgrawal sí, ese es el punto. Async / await le permite escribir código asíncrono en un estilo sincrónico para que pueda evitar el "infierno de devolución de llamadas" y encadenar muchas promesas juntas. Es una forma muy divertida de escribir código asíncrono en mi opinión
Dana Woodman
Entonces, ¿cuál es el beneficio de usar JavaScript si estamos haciendo que el código asíncrono sea síncrono? porque la mayoría de las personas usan JavaScript debido a su naturaleza asíncrona
Atul Agrawal
2
@AtulAgrawal obtienes lo mejor de ambos mundos: disfrutas de la naturaleza asíncrona del lenguaje (ya que el código anterior aún se ejecutará asíncrono, liberando el hilo y todo) y aprovechando los beneficios de un estilo de codificación más amigable para el programador. Sin embargo, no está exento de problemas ...
ZenMaster
15

try-catch en javascript es tan válido y útil como en cualquier otro idioma que los implemente. Hay una razón importante por la que no se usa tanto en JavaScript como en otros idiomas. Es la misma razón por la que JavaScript se ve como un lenguaje de script feo, es la misma razón por la que la gente piensa que los programadores de JavaScript no son programadores reales:

  • Javascript es un lenguaje increíblemente accesible y dominante

El mero hecho de que tantas personas estén expuestas a JavaScript (en virtud del único idioma admitido por los navegadores) significa que tiene un montón de código no profesional. Por supuesto, también hay muchas razones menores:

  • algunas cosas en javascript son asincrónicas y, por lo tanto, no son catchcapaces (cosas asincrónicas)
  • Se ha hablado mucho sobre cómo Try-catch tiene un gran éxito en el rendimiento. Tiene un poco de éxito en el rendimiento , pero para la mayoría de los códigos, vale la pena.
  • JavaScript (desafortunadamente) se implementó de una manera que a menudo ignora silenciosamente los errores (por ejemplo, cambiar automáticamente las cadenas a números)

De todos modos, debe usarse try-catch , pero por supuesto, debe aprender a usarlos correctamente , como todo lo demás en programación.

user250878
fuente
3
¿Y por qué alguna vez votaste mal, oh silencioso votante?
user250878
Convenido. Creo que la respuesta aceptada es generalmente cierta, pero hay buenas razones para usar try-catch e incluso tirar, aparte de cuando se trata de objetos nativos. Cuando se arroja un error en lugar de pasarlo a una devolución de llamada, se detiene la ejecución adicional y se sube la pila al primer bloque que puede manejarlo. Esta es una gran ventaja y tiene mucho sentido para las operaciones sincrónicas, especialmente si implican un anidamiento profundo. Parece una locura sugerir que las excepciones son "malas" (bueno, aparte de las razones obvias), en realidad son una herramienta muy útil con un "poder" único.
Semicolon
2
¿Alguna vez se tomó el tiempo de leer el código fuente de, por ejemplo, jQuery? Casi ningún intento de captura allí, excepto exactamente los escenarios mencionados en la respuesta aceptada: para detectar características y usar objetos nativos / host que arrojan errores. Llamar código que no usa try-catch mucho (como jQuery) 'poco profesional' parece una tontería. Para ser honesto, creo que son los programadores Javascript especialmente nuevos que provienen de Java los que tienden a usar en exceso las características del lenguaje como try-catch.
Stijn de Witt
6

Creo que gran parte de la razón que try..catches rara en JavaScript es porque el lenguaje tiene una tolerancia bastante alta al error. La gran mayoría de las situaciones se pueden manejar mediante el uso de comprobaciones de código, buenos valores predeterminados y eventos asincrónicos. En algunos casos, simplemente usar un patrón evitará problemas:

function Foo() {
    //this may or may not be called as a constructor!!
    //could accidentally overwrite properties on window
}

function Bar() {
    if (!(this instanceof Bar)) {
        return new Bar();
    }
    //this will only work on Bar objects, and wont impact window
}

Algunos de los principales problemas en otros idiomas que causan excepciones simplemente no existen en JS. La conversión de tipos no es necesaria la gran mayoría de las veces. En cambio, el método preferido suele ser la verificación de características (hacer cumplir una interfaz particular):

function doFoo(arg) {
    if (arg.foo) {
        arg.foo();
    } else {
        Bar.prototype.foo.call(arg);
    }
}

Con la adición de async/ awaital idioma, try..catchcada vez es más frecuente. Promete ser la forma asincrónica de try..catch, tiene sentido que uno deba esperar:

doSomething().then(
  doSomethingWithResult,
  doSomethingWithError
)

en lugar de ser escrito como:

try {
  const result = await doSomething()
  doSomethingWithResult(result)
} catch (e) {
  doSomethingWithError(e)
}
zzzzBov
fuente
3

Posiblemente otra razón por la que try / catch no se usa mucho en Javascript es que la construcción no estaba disponible en las primeras versiones de Javascript ... se agregó más tarde.

Como resultado, algunos navegadores antiguos no lo admiten. (De hecho, puede causar un error de analizador / sintaxis en algunos navegadores más antiguos, algo más difícil de "programar a la defensiva" que la mayoría de los otros tipos de errores).

Más importante aún, dado que no estaba disponible inicialmente, las funciones incorporadas de Javascript que se lanzaron inicialmente (lo que uno llamaría las funciones de "biblioteca" en muchos idiomas) no la utilizan. (No funciona muy bien "detectar" un error de someobject.somefunction () si no "arroja", sino que simplemente devuelve "nulo" cuando encuentra un problema).


Otra posible razón es que el mecanismo de prueba / captura no parecía ser necesario inicialmente (y todavía no parece tan útil). Realmente es necesario solo cuando las llamadas se anidan habitualmente en varios niveles de profundidad; simplemente devolver algún tipo de ERRNO funcionaría bien para llamadas directas (aunque para que sea realmente útil siempre que esté disponible, la mejor práctica en la mayoría de los idiomas es usarlo en todas partes en lugar de solo en llamadas profundamente anidadas). Como originalmente se esperaba que la lógica de Javascript fuera pequeña y simple (después de todo, es solo un complemento de una página web :-), no se esperaba que las llamadas a funciones estuvieran profundamente anidadas, por lo que no parecía necesario un mecanismo de prueba / captura.

Chuck Kollars
fuente
3
No no no, absolutamente no es el caso. Los motores tan antiguos ya no importan durante mucho tiempo y la comunidad de JavaScript en general se deshace rápidamente de las cosas viejas cuando está justificado. Incluso apostaría a que la mayoría de los desarrolladores de JavaScript ahora son posteriores a IE6.
Camilo Martin
0

Creo que no se usan tanto porque lanzar excepciones en el código del lado del cliente Javascript hace que sea más difícil depurar una página.

En lugar de lanzar excepciones, generalmente prefiero mostrar un cuadro de alerta, (es decir alert("Error, invalid...");)

Puede sonar extraño, pero los errores de Javascript ocurren en el lado del cliente, si un cliente está usando una página que usted creó y la página arroja una excepción, a menos que el cliente sea un experto en tecnología, no hay forma de que él pueda saberlo usted cuál es el problema.

Solo te llamará para decirte: "¡Oye, la página X no funciona!", Y luego dependerá de ti encontrar qué salió mal y en qué parte del código.

Al usar el cuadro de alerta en su lugar, es más probable que llame y diga algo como: "Oye, cuando hago clic en el botón A de la página X muestra un cuadro que dice ..." , confía en mí, será mucho más fácil de encontrar el bicho.

Marco Demaio
fuente