mozilla
Los resultados de tu búsqueda

    Control de flujo y manejo de errores

    Este articulo necesita una revisión editorial.

    This translation is incomplete. Please help translate this article from English.

    Javascript soporta un conjunto compacto de sentencias específicas para el manejo de flujo, que pueden ser utilizadas para incorporar mayor interactividad a tus aplicaciones. Este capítulo provee una vista general de las mismas.

    La guía de referencia de Javascript contiene detalles exhaustivos sobre las sentencias mencionadas en este capítulo. El punto y coma (;) se utiliza para separar sentencias de código Javascript.

    En Javascript cualquier expresión es también una sentencia. Puedes ver Expresiones y operadoes para más información sobre expresiones.

    Bloque de sentencias

    El bloque es el tipo de sentencia más básico y se utiliza para agrupar sentencias. El bloque se delimita entre un par de llaves:

    {
      sentencia_1;
      sentencia_2;
      .
      .
      .
      sentencia_n;
    }
    

    Ejemplo

    El bloque es comúnmente utilizado para el control de flujo  (ej. if, for, while).

    while (x < 10) {
      x++;
    }
    

    En este caso { x++; } es un bloque de sentencias.

    Importante: Javascript no tiene scope a nivel bloque en versiones anteriores a ECMAScript 6. Las variables introducidas dentro de un bloque pertenecen a la función o script que lo contiene y el efecto de setarlos persiste más alla del bloque mismo. En otras palabras, los bloques no introducen un nuevo scope. Si bien los bloques "standalone" son válidos no deberían ser utilizados en Javascript ya que no se comportan como los bloques de C o Java. Por ejemplo:

    var x = 1;
    {
      var x = 2;
    }
    console.log(x); // imprime 2
    

    Este código imprime el número 2 ya que la sentencia de la variable x dentro del bloque está en el mismo scope que la variable x definida antes del bloque. En C o Java el equivalente de este código imprimiría 1.

    A partir de ECMAScript 6, se introduce el scope a nivel bloque utilizando let para declarar las variables.

    Condicionales

    Un condicional es un set de comandos que se ejecutan si una condición es verdadera. JavaScript soporta dos condicionales: if...else y switch

    if...else

    Se utiliza if para ejecutar una sentencia si la condición lógica es verdadera. Se utiliza la opción else para ejecutar un sentencia si la condición es falsa. A continuación se muestra un ejemplo de if...else:

    if (condición) {
      sentencia_1;
    } else {
      sentencia_2;
    }

    La condición puede ser cualquier expresión que evalua a true o false. Consultar Boolean para una explicación de como se evalua true y false. Si la condición es verdadera, sentencia_1 se ejecutra; si no, sentencia_2 se ejecuta. La sentencia_1 y la sentencia_2 pueden cualquiera, incluyendo sentecias anidadas en if.

    Esto tambien se puede complicar usando else if para tener multiples condiciones, como a continuación:

    if (condición_1) {
      sentencia_1;
    } else if (condición_2) {
      sentencia_2;
    } else if (condición_n) {
      sentencia_n;
    } else {
      ultima_sentencia;
    } 
    

    Para ejecutar multiples sentencias, agrupalas dentro de sentencias de bloque ({ ... }) . En general, usar siempre sentencias de bloque es una buena práctica, sobre todo cuando se anidan sentencias if:

    if (condición) {
      ejecutar_sentencia_1_si_condición_es_verdadera;
      ejecutar_sentencia_2_si_condición_es_verdadera;
    } else {
      ejecutar_sentencia_3_si_condición_es_falsa;
      ejecutar_sentencia_4_si_condición_es_falsa;
    }
    
    Se aconseja no usar asiganción simple dentro de una expresión condicional porque dicha asignación puede ser confundida con el comparador de igualdad cuando se lee de pasada el código. Por ejemplo, no uses el siguiente código:
     
    if (x = y) {
      /* sentencias aquí */
    }
    

    Si necesitas usar una asignación dentro de una expresión de condición, una práctica común es poner paréntesis adicionales alrededor de la asignación. Por ejemplo:

    if ((x = y)) {
      /* sentencias aquí */
    }
    

    Valores falsos:

    Los siguientes valores se evaluarán como falso:

    • false
    • undefined
    • null
    • 0
    • NaN
    • la cadena vacía ("")

    El resto de valores, incluidos todos los objetos, son evaluados como verdadero cuando son pasados a una sentencia condicional.

    No confundir los valores primitivos booleanos true y false con el verdadero y falso del objeto Boolean. Por ejemplo:

    var b = new Boolean(false);
    if (b) // Esta condición se evalua a true
    

    Ejemplo

    En el siguiente ejemplo, la función comprobarDatos devuelve verdadero si el número de caracteres en un objeto Text es tres; en otro caso, muestra una alerta y devuelve falso.

    function comprobarDatos() {
      if (document.form1.threeChar.value.length == 3) {
        return true;
      } else {
        alert("Introduce exactamente tres caracteres. " +
        document.form1.threeChar.value + " no es válido.");
        return false;
      }
    }
    

    switch

    Una sentencia switch permite a un programa evaluar una expresión e intentar encajar el valor de dicha expresión a una etiqueta de caso. Si se encuentra una coincidencia, el programa ejecuta la sentencia asociada. Una sentencia switch se describe como se muestra a continuación:

    switch (expresión) {
      case etiqueta_1:
        sentencias_1
        [break;]
      case etiqueta_2:
        sentencias_2
        [break;]
        ...
      default:
        sentencias_por_defecto
        [break;]
    }
    

    El programa primero busca una claúsula case con una etiqueta que coincida con el valor de la expresión y, entonces, transfiere le control a esa cláusula, ejecutando las sentencias asociadas a ella. Si no se encuentran etiquetas coincidentes, el programa busca la cláusula opcional default y, si se encuentra, transfiere el control a esa cláusula, ejecutando las sentencias asociadas. Si no se encuentra la cláusula default, el programa continúa su ejecución por la siguiente sentencia al final del switch. Por convención, la cláusula por defecto es la última cláusula, aunque no es necesario que sea así.

    La sentencia opcional break asociada con cada cláusula case asegura que el programa finaliza la sentencia switch una vez que la sentencia asociada a la etiqueta coincidente es ejecutada y continúa la ejecución por las sentencias siguientes a la sentencia switch. Si se omite la sentencia break, el programa continúa su ejecución por la siguiente sentencia que haya en la sentencia switch.

    Ejemplo

    En el siguiente ejemplo, si tipoFruta se evalúa como "Plátanos", el programa encaja el valor con el caso "Plátanos" y ejecuta las sentencias asociadas. Cuando se encuentra la sentencia break, el programa termina el switch y ejecuta las sentencias que le siguen. Si la sentencia break fuese omitida, la sentencia para el caso "Cerezas" también sería ejecutada.

    switch (tipoFruta) {
      case "Naranjas":
        console.log("Naranjas cuestan 0,59€ el kilo.");
        break;
      case "Manzanas":
        console.log("Manzanas cuestan 0,32€ el kilo.");
        break;
      case "Plátanos":
        console.log("Plátanos cuestan 0,48€ el kilo.");
        break;
      case "Cerezas":
        console.log("Cerezas cuestan 3,00€ el kilo.");
        break;
      case "Mangos":
        console.log("Mangos cuestan 0,56€ el kilo.");
        break;
      case "Papayas":
        console.log("Mangos y papayas cuestan 2,79€ el kilo.");
        break;
      default:
       console.log("Disculpa, no tenemos el tipo de fruta " + fruittype + ".");
    }
    console.log("¿Te gustaría tomar algo?");

    Sentencias de manejo de excepciones

    Puedes lanzar excepciones usando la sentencia throw y manejarlas usando las sentencias try...catch.

    Tipos de excepciones

    Practicamente cualquier objecto puede ser lanzado en JavaScript. Sin embargo, no todos los objetos lanzados son creados igual. Mientras que es bastante común para lanzar números o strings como errores, frecuentemente son más efectivos utilizar uno de los tipos de excepciones especificamente creados para este proposito:  

    Sentencia throw 

    Utiliza la sentencia throw  para lanzar una excepción. Cuando lanzas un excepción, se especifica la expresión que contiene el valor para ser lanzado:

    throw expresión;
    

    Puedes lanzar cualquier expresión, no solo espresiones de un tipo espacifico. En el siguente código lanzamos varias excepciones de varios tipos: 

    throw "Error2";   // Tipo string
    throw 42;         // Tipo número
    throw true;       // Tipo booleano
    throw {toString: function() { return "¡Soy un objeto!"; } };
    
    Note: Puedes especificar un objeto cuando lanzas una excepción. A continuación, puedes hacer referencia a las propiedades del objeto en un bloque catch. En el siguiente ejemplo se crea un objeto myUserException del tipo UserException y lo usa en la sentencia throw.
    // Crear un tipo de objeto UserException
    function UserException (aviso){
      this.aviso=aviso;
      this.nombre="UserException";
    }
    
    // Make the exception convert to a pretty string when used as a string 
    // (e.g. by the error console)
    UserException.prototype.toString = function () {
      return this.name + ': "' + this.message + '"';
    }
    
    // Create an instance of the object type and throw it
    throw new UserException("Value too high");

    try...catch

    La sentencia try...catch marca un bloque de instrucciones a intentar que pueden causar alguna excepción, y declarar una o más respuestas en caso de que una excepción sea arrojada. Si una excepción es arrojada, la sentencia try...catch se encarga de atraparla.

    La sentencia try...catch consiste en un bloque try, el cuál contiene una o más instrucciones, y ninguno o varios bloques catch, conteniendo sentencias que especifican que hacer si una excepción es arrojada en un bloque try. Se desea que las instrucciones dentro del bloque try se ejecuten con éxito, de caso contrario caerán en el bloque catch para ser controladas. Si ninguna instrucción dentro del bloque try (o en una función llamada dentro del bloque try) arroja una excepción, el control pasa inmediatamente al bloque catch. Si ninguna excepción es arrojada en el bloque try, el bloque catch es ignorado. Por último se ejecuta el bloque finally luego de que los bloques try y catch hayan sido ejecutados pero antes de las instrucciones que se encuentren luego de la sentencia try...catch.

    El siguiente ejemplo usa la sentencia try...catch. El ejemplo llama a una función que retorna el nombre de un mes desde un arreglo basado en un valor pasado como argumento a la función. Si el valor no corresponde con el número de un mes (entre 1 y 12), una excepción es arrojada con el valor "InvalidMonthNo" y las instrucciones en el bloque catch le asignarán a la variable monthName el valor de unknown.

    function getMonthName (mo) {
      mo = mo-1; // Ajusta el indice del arreglo para el arreglo de meses (1=Jan, 12=Dec)
      var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul",
                    "Aug","Sep","Oct","Nov","Dec"];
      if (months[mo] != null) {
        return months[mo];
      } else {
        throw "InvalidMonthNo"; //Arroja la palabra "InvalidMonthNo" al ocurrir una excepción
      }
    }
    
    try { // instrucciones a probar
      monthName = getMonthName(myMonth); // La función puede arrojar una excepción
    }
    catch (e) {
      monthName = "unknown";
      logMyErrors(e); // Pasa el objeto de la excepción a un manejador de errores
    }
    

    El bloque catch

    Un bloque catch es usado para manejar todas las excepciones que pueden ser generadas en el bloque try.

    catch (catchID) {
      instrucciones
    }
    

    El bloque catch especifica un identificar (catchID en la sintaxis anterior) que mantiene el valor especificado por la sentencia thrown; puedes usar este identificador para obtener información acerca de la excepción que fue arrojada. JavaScript crea este identificador cuando ha entrado en el bloque catch; el identificador dura mientras dure el bloque catch; después de que el bloque catch termine su ejecución, el identificador ya no está disponible.

    Por ejemplo, el siguiente código arroja una excepción. Cuando la excepción ocurre, el control es transferido al bloque catch.

    try {
      throw "myException" // genera una excepción
    }
    catch (e) {
      // instrucciones para manejar cualquier excepción generada
      logMyErrors(e) // Pasa el objeto de excepción a un manejador de errores
    }
    

    El bloque finally

    El bloque finally contiene instrucciones para ejecutar luego de la ejecución del bloque try y el bloque catch pero antes de las instrucciones ubicadas luego de la sentencia try...catch. El bloque finally se ejecuta se haya arrojado o no una excepción. Si una excepción es arrojada, las instrucciones en el bloque finally se ejecutan incluso si no existe un bloque catch que maneje la excepción.

    Se puede usar el bloque finally para hacer que tu script falle con gracia cuando una excepción ocurre; por ejemplo, puedes tener la necesidad de liberar un recurso que tu script tiene ocupado. El siguiente ejemplo abre un archivo y luego ejecuta instrucciones que usan el archivo (JavaScript del lado del servidor permite acceder a archivos). Si una excepción es arrojada mientras el archivo está abierto, el bloque finally cierra el archivo antes de que el script falle.

    openMyFile();
    try {
      writeMyFile(theData); // Esto puede arrojar un error
    } catch(e) {  
      handleError(e); // Si ocurre un error es manejado
    } finally {
      closeMyFile(); // Siempre cierra el recurso
    }
    

    Si el bloque finally retorna un valor, este valor se convierte en el valor de retorno de toda la sentencia try-catch-finally, independientemente de cualquier sentencia return en el bloque try y el bloque catch:

    function f() {
      try {
        console.log(0);
        throw "bogus";
      } catch(e) {
        console.log(1);
        return true; // Esta sentencia de retorno es suspendida
                     // hasta que el bloque finally esté completo
        console.log(2); // no alcanzable
      } finally {
        console.log(3);
        return false; // sobreescribe la sentencia de retorno anterior
        console.log(4); // no alcanzable
      }
      // "return false" es ejecutada ahora
      console.log(5); // no alcanzable
    }
    f(); // alerts 0, 1, 3; retorna false
    

    Sobreescribiendo los valores retornados por el bloque finally también aplica a excepciones arrojadas o relanzadas dentro de un bloque catch:

    function f() {
      try {
        throw "bogus";
      } catch(e) {
        console.log('caught inner "bogus"');
        throw e; // Esta sentencia throw es suspendida hasta que
                 // el bloque finally se termine de ejecutar
      } finally {
        return false; // Sobreescribe la sentencia throw anterior
      }
      // "return false" es ejecutado ahora
    }
    
    try {
      f();
    } catch(e) {
      // Esta nunca es encontrada porque la sentencia throw dentro
      // del bloque catch es sobrescrita por la sentencia return
      // en el bloque finally
      console.log('caught outer "bogus"');
    }
    
    // SALIDA
    // atrapado dentro de "bogus"

    Sentencias try...catch anidadas

    Es posible anidad una o más sentencias try...catch. Si una sentencia try...catch interna no posee un bloque catch, la sentencia try...catch exterior verifica si el bloque exterior genera una coincidencia.

    Utilizando objetos de Error

    Dependiendo del tipo de error, es posible usar el 'name' (nombre) y el 'message' (mensaje) propiedades para obtener un mensaje más refinado. La propiedad 'name' provee la clase general del Error(por ejemplo, 'DOMException' or 'Error'), mientras que la propiedad 'message' por lo general provee un breve mensaje que puede ser obtenido convirtiendo el error de object a string.

    Si estás arrojando tus propias excepciones, en orden para tomar ventaja de estas propiedades (Como si tu bloque catch no discrimina entre tus propias excepciones y las excepciones del sistema), puedes usar el constructor de Error. Por ejemplo:

    function doSomethingErrorProne () {
      if (ourCodeMakesAMistake()) {
        throw (new Error('The message'));
      } else {
        doSomethingToGetAJavascriptError();
      }
    }
    ....
    try {
      doSomethingErrorProne();
    }
    catch (e) {
      console.log(e.name); // logs 'Error'
      console.log(e.message); // logs 'The message' o un error de JavaScript)
    }

    Promises

    Empezando con ECMAScript 6, Javascript gana soporte para Promise objetos que permiten tomar el control del flujo o diferidas operaciones asincronas.

    Una Promise puede estar ubicada en estos estados:

    • pending: Estado inicial, ni terminada exitosamente o rechazada.
    • fulfilled: operación exitosa.
    • rejected: operación fallida o rechazada.
    • settled: la Promise ha sido exitosa o rechazada, pero no está pendiente.

    Cargando una imagen con XHR

    Un simple ejemplo del uso de Promise y XMLHttpRequest es cargar una imagen que está disponible en el repositorio promise-test de MDN GitHub. Puedes verlo también en acción. Cada paso es comentado y permite que sigas la arquitectura de la Promise y XHR de cerca. Aquí está una versión sin comentar, mostrando el flujo de una Promise para que puedas tener una idea:

    function imgLoad(url) {
      return new Promise(function(resolve, reject) {
        var request = new XMLHttpRequest();
        request.open('GET', url);
        request.responseType = 'blob';
        request.onload = function() {
          if (request.status === 200) {
            resolve(request.response);
          } else {
            reject(Error('Image didn\'t load successfully; error code:' 
                         + request.statusText));
          }
        };
        request.onerror = function() {
          reject(Error('There was a network error.'));
        };
        request.send();
      });
    }

    Para información más detallada, visitar Promise como página de referencia.

    Etiquetas y colaboradores del documento

    Contributors to this page: MaFranceschi, Cleon, humbertaco, fscholz, isnardi
    Última actualización por: MaFranceschi,
    Ocultar la barra lateral