try...catch

Estás leyendo la versión en inglés del artículo porque aún no existe una traducción para este idioma. ¡Ayúdanos a traducir este artículo!

La declaración try...catch señala un bloque de instrucciones a intentar (try), y especifica una respuesta si se produce una excepción (catch).

Sintaxis

try {
   try_statements
}
[catch (exception_var_1 if condition_1) { // non-standard
   catch_statements_1
}]
...
[catch (exception_var_2) {
   catch_statements_2
}]
[finally {
   finally_statements
}]
try_statements
Las sentencias que serán ejecutadas.
catch_statements_1, catch_statements_2
Sentencias que se ejecutan si una excepción es lanzada en el bloque try.
exception_var_1, exception_var_2
Identificador que contiene un objeto de excepcion asociado a la cláusula catch.
condition_1
Una expresión condicional.
finally_statements
Sentencias que se ejecutan después de que se completa la declaración try . Estas sentencias se ejecutan independientemente de si una excepcion fue lanzada o capturada.

Descripción

La declaración try consiste en un bloque try que contiene una o más sentencias (se debe usar siempre {} incluso para una sola sentencia) y al menos una cláusula catch o una cláusula finally, o bien ambas. Esto nos da tres formas posibles para la declaración try:

  1. try...catch
  2. try...finally
  3. try...catch...finally

Un bloque catch contiene sentencias que especifican que hacer si una excepción es lanzada en el bloque try . Es decir, usted quiere que el bloque try tenga éxito, pero si éste no lo tiene, usted quiere que el control pase al bloque catch. Si cualquier sentencia dentro del bloque try (o en una funcion llamada desde dentro del bloque try) lanza una excepción, el control cambia inmediatamente a la cláusula catch . Si ninguna excepcion es lanzada en el bloque try , la clausula catch se omite.

La cláusula finally se ejecuta despues del bloque try  y la(s) clausula(s) catch pero antes de las instrucciones que siguen a la declaración try. Ésta siempre se ejecuta, independientemente de si una excepción fue lanzada o capturada.

Puede anidar una o más sentencias try. Si una declaración try interna no tiene una cláusula catch, se ejecuta la cláusula catch de la declaración try que la encierra.

Usted también puede usar la declaración try para manejar excepciones de JavaScript. Consulte la Guía de JavaScript para obtener mayor información sobre excepciones de JavaScript.
 

Cláusula incondicional catch

Cuando una única cláusula incondicional catch es usada, el bloque catch es ejecutado cuando cualquier excepción es lanzada. Por ejemplo, cuando la excepción ocurre en el siguiente código, el control se transfiere a la cláusula catch.

try {
   throw "myException"; // genera una excepción
}
catch (e) {
   // sentencias para manejar cualquier excepción
   logMyErrors(e); // pasa el objeto de la excepción al manejador de errores
}

El bloque catch especifíca un identificador ( e en el ejemplo de arriba) que contiene el valor especificado por la sentencia throw. JavaScript crea este identificador cuando el bloque catch es ejecutado y lo agrega al ámbito actual; el identificador persiste solo durante la ejecución del bloque catch; después de que este términa de ejecutarse, el identificador ya no está disponible más.

Cláusulas condicionales catch

No estándar
This feature is non-standard and is not on a standards track. Do not use it on production sites facing the Web: it will not work for every user. There may also be large incompatibilities between implementations and the behavior may change in the future.

Usted también puede usar una o más cláusulas condicionales catch para manejar excepciones específicas. En este caso, la cláusula catch apropiada es ejecutada cuando la excepción específica es lanzada. En el siguiente ejemplo, el código en el bloque try puede potencialmente lanzar tres excepciones TypeError, RangeError, y EvalError. Cuando una excepción ocurre, el control se transfiere a la cláusula catch apropiada. Si la excepción no es una de las excepciones especificadas y una cláusula catch incondicional es encontrada, el control se transfiere a esa cláusula catch.

Si usted usa una cláusula catch incondicional con una o más cláusulas catch condicionales, la cláusula catch incondicional debe ser especificada al último. De otra forma, la cláusula catch incondicional interceptará todo tipo de excepciones antes de que puedan alcanzar las condicionales.

Recordatorio: ésta funcionalidad no es parte de la especificación ECMAScript y ha sido removida en Firefox 59. No es soportada en ningún navegador actuál.

try {
   myroutine(); // puede lanzar tres tipos de excepciones
} catch (e if e instanceof TypeError) {
   // sentencias para manejar excepciones TypeError
} catch (e if e instanceof RangeError) {
   // sentencias para manejar excepciones RangeError
} catch (e if e instanceof EvalError) {
   // sentencias para manejar excepciones EvalError
} catch (e) {
   // sentencias para manejar cualquier excepción no especificada
   logMyErrors(e); // pasa el objeto de la excepción al manejador de errores
}

Y aquí está cómo implementar las mismas "Cláusulas catch condicionales" conforme a la especificación ECMAScript (obviamente es más verboso, pero funciona en cualquier parte):

try {
    // puede lanzar tres tipos de excepciones
    myroutine();  
} catch (e) {
    if (e instanceof TypeError) {
        // sentencias para manejar excepciones TypeError
    } else if (e instanceof RangeError) {
        // sentencias para manejar excepciones RangeError
    } else if (e instanceof EvalError) {
        // sentencias para manejar excepciones EvalError
    } else {
       // sentencias para manejar cualquier excepción no especificada
       logMyErrors(e); // pasa el objeto de la excepción al manejador de errores
}

El identificador de excepciones

Cuando una excepción es lanzada en el bloque try, exception_var (por ejemplo, la e en catch (e)) guarda el valor especificado por la sentencia throw. Usted puede usar éste identificador para obtener información acerca de la excepción que fue lanzada. Éste identificador es local a la cláusula catch. Esto significa que, es creado cuando la cláusula catch es ejecutada, y después de que termine de ejecutarse, el identificador no estará disponible más.

La cláusula finally

La cláusula finally contiene sentencias a ejecutarse después de que las cláusulas try y catch se ejecuten, pero antes de las sentencias que le siguen al bloque try..catch..finally. Note que la cláusula finally se ejecuta sin importar si una excepción es o no lanzada. Si una excepción es lanzada, las instrucciones en la cláusula finally se ejecutan incluso si ninguna cláusula catch maneja la excepción.

Usted puede usar la cláusula finally para hacer que su script falle plácidamente cuando una excepción ocurra; por ejemplo, para hacer una limpieza general, usted puede necesitar liberar un recurso que su script haya retenido.

Puede parecer extraño tener una cláusula relacionada a una excepción que se ejecuta sin importar si hay una excepción o no, pero esta concepción en realidad sirve a un propósito. El punto importante no es que la cláusula finally siempre se ejecuta, si no más bien que el codigo ordinario que le sigue a try..catch no.

Por ejemplo, si otra excepción ocurre dentro de un bloque catch de una declaración try, cualquier codigo restante en el mismo bloque exterior try que encierra ese try..catch (o en el flujo principal, si no es un bloque try exterior) , no será ejecutado, dado que el control es inmediatamente transferido al bloque catch del try exterior (o el generador de error interno, si no es en un bloque try).

Por lo tanto, cualquier rutina de limpieza hecha en esa sección encerrada (o la principal) antes de que exista, será saltada. Sin embargo, si la declaración try tiene un bloque finally, entonces el código de ese bloque finally será ejecutado primero para permitir tal limpieza, y ENTONCES el bloque catch de la otra declaración try (o el generador de error) tomará el control para manejar la segunda excepción.

Ahora, si esa rutina de limpieza debiera ser hecha ya sea que el código del try..catch tenga éxito o no, entonces si el bloque finally se ejecutase solo después de una excepción, el mismo código de limpieza tendría que estar presente dentro y fuera del bloque finally, y por lo tanto no hay razón para no tener el bloque finally solo, y dejarlo ejecutarse sin importar si hay excepciones o no.

El siguiente ejemplo abre un archivo y despues ejecuta sentencias que usan el archivo (JavaScript del lado del servidor permite acceder a archivos). Si una excepción es lanzada mientras el archivo está abierto, la cláusula finally cierra el archivo antes de que el script falle. El código en finally también se ejecuta después de un retorno explícito de los bloques try o catch.

openMyFile()
try {
   // retiene un recurso
   writeMyFile(theData);
}
finally {
   closeMyFile(); // siempre cierra el recurso
}

Ejemplos

Bloques try anidados

Primero, veamos que pasa con esto:

try {
  try {
    throw new Error('oops');
  }
  finally {
    console.log('finally');
  }
}
catch (ex) {
  console.error('outer', ex.message);
}

// Output:
// "finally"
// "outer" "oops"

Ahora, si nosotros ya capturamos la excepción en una declaración try interna agregando un bloque catch.

try {
  try {
    throw new Error('oops');
  }
  catch (ex) {
    console.error('inner', ex.message);
  }
  finally {
    console.log('finally');
  }
}
catch (ex) {
  console.error('outer', ex.message);
}

// Output:
// "inner" "oops"
// "finally"

Y ahora vamos a relanzar el error.

try {
  try {
    throw new Error('oops');
  }
  catch (ex) {
    console.error('inner', ex.message);
    throw ex;
  }
  finally {
    console.log('finally');
  }
}
catch (ex) {
  console.error('outer', ex.message);
}

// Output:
// "inner" "oops"
// "finally"
// "outer" "oops"

Cualquier excepción dad será capturada solo una vez por el bloque catch más cercano a menos que sea relanzado. Por supuesto cualquier nueva excepción que se origine en el bloque 'interno' (porque el código en el bloque catch puede hacer algo que lanze un error), será capturado por el bloque 'externo'.

Retornando de un bloque finally

Si el bloque finally retorna un valor, este valor se convierte en el valor de retorno de toda la producción try-catch-finally, a pesar de cualquier sentencia return en los bloques try y catch. Esto incluye excepciones lanzadas dentro del bloque catch.

(function() {
  try {
    try {
      throw new Error('oops');
    }
    catch (ex) {
      console.error('inner', ex.message);
      throw ex;
    }
    finally {
      console.log('finally');
      return;
    }
  }
  catch (ex) {
    console.error('outer', ex.message);
  }
})();

// Output:
// "inner" "oops"
// "finally"

El "oops" externo no es lanzado debido al retorno en el bloque finally. Lo mismo aplicaría para cualquier valor retornado del bloque catch.

Vea los ejemplos para throw.

Vea también